The online racing simulator
Hi, Dark Times - or others!

Again I have a little problem to be solved:

I can connect to every host specified in a dictionary and then I can send a message to the host.

But what I would like to do is to send a message to every host in my dictionary every lets say 5 minutes...

I tryed doing it with a timer but it only works for the last connected server - but the message is not sent to all connected servers, it is sent e.g. twice to the last server if I have 2 Server in mx Dictionary:

def timer_message():
for socket in sockets:
sendmessage('/msg Welcome'
timer = threading.Timer(300, timer_message)

an other way I tried was:


for socket in sockets:
if socket.Connected == True:
socket.SendP(Pyinsim.Packet(Pyinsim.ISP_ISI, Admin=Adminpass,
IName='^3app', ReqI=1))

while a == 0:
SendMessage('/unban ' + unbans)
a = 0

but here it only connects to the last server - which is sounding quite logical because the program has an endless loop...
OMG... there is the next idea I need your help for:

Is it possible to place a small button file which opens a list of all connected racer as buttons?

But only connected racers in a special config file should be able to see this button..

Then I can click on a Racer Name and a code will be executed with the racers licence name?

I would like to add the licence names of racers I clicked on to a text file to handle lapper options with them...
Quote from Crady :

for socket in sockets:
if socket.Connected == True:
socket.SendP(Pyinsim.Packet(Pyinsim.ISP_ISI, Admin=Adminpass,
IName='^3app', ReqI=1))

[B]while a == 0:
SendMessage('/unban ' + unbans)
a = 0[/B]

This is an infinite loop, it just keeps looping over the same code again and again, and the program never progresses past this point.

Based on the earlier code posted, I knocked up a quick example of how you could do this:

import Pyinsim
import threading

hosts = {'': 29999}
sockets = []
timer = None

def SendMessage(socket, msg):
"""Send message to specific socket."""
socket.SendP(Pyinsim.Packet(Pyinsim.ISP_MST, Msg=msg))

def TimerElapsed():
"""Function called when the timer finishes."""
for socket in sockets:
SendMessage(socket, "Hello")
# Start the timer again.

def StartTimer():
"""Starts the timer."""
timer = threading.Timer(300, TimerElapsed)

for host, port in hosts.iteritems():
# Loop through each host, connect and initailise it, then add it
# to sockets list.
insim = Pyinsim.InSim()
insim.Connect(host, port)
insim.SendP(Pyinsim.Packet(Pyinsim.ISP_ISI, Admin='pass', IName='^3XXX', ReqI=1))

# Start the timer.

for socket in sockets:

Hope that helps some.
Dark Times,

again and again... Thank you

works like charme

Next aim will be the button things... Do you have a usefull manual for creating buttons - I mean either I will need a mall button which opens a bigger button to type text in (which could be used later) or I will need a small button to display a clickable drivers list which gives me the licence name into a variable...
Dark Times,

Does pyinsim0.1.6 also run with python2.6 or do I have to sty at 2.5.2?
edit: irrelevant.
edit: irrelevant.
edit: irrelevant.
I downloaded Python 2.5.4 and Pyinsim 0.1.9, but the installation doesn't work on Windows Vista. Windows just report that it's unable to run the file. What should I do?
I don't know why it doesn't work on Vista. You can just unzip the and copy the file into the same directory as your program's files.
I tried to do it manually, but I probably moved it to bad directory or I don't know. I moved it to Python25\Lib\site-packages\ and when I ran insim program written in python, it immediately shutted down as usually without pyinsim library which means it didn't work.

So I copied Python25 folder from my computer running on Windows XP and it worked.
Under Vista you have to execute the installer as Administrator. Otherwise it will not work...
On a random note, I was playing around with NetBeans 6.5 today, which has newly integrated support for Python, and it seems to work great! What struck me most was some very comprehensive auto-completion (although still not as good as WingIDE), and especially an excellent inline debugger. Definietly a nice free alternative to the costly WingIDE, the bloated Eclipse and the endearingly homemade Stani's Python Editor. Definietly one to watch, as this is just the first version.
Attached images
Thank you! I am using eclipse...
Great Work!
Hey DarkTimes!

Your Pyinsim is a very nice work! Thanks for that.

After my first tries with python some years (?) ago, when marcoz released his RaceManager, i stopped due to some issues.

Now i started again with python and insim, and it seems much nicer with pyinsim and the new insim than before.

After struggling the last days with some differences between the .py-sources in the forum and the pyinsim-template (with/without Player-class/player-npl-list), i think I'm now back in business to do my last insim-stat ideas with python.

I found, that GetTimeStr() from doesn't work as expected.
Here's my noobish workaround (not fully tested).

def GetTimeStr(self):
"""Get a string representing the time (h:mm:ss.ttt).

A string representing the time.

return '%d:%.2d[B]:%.2d[/B].%.3d' % (self.GetHours(), [B]int([/B]self.GetMinutes() [B]% 60),[/B]
self.GetSeconds(), self.GetMilliseconds())

Cu later... (thread subscribed)

BTW: Sorry for my bad English.
OK - thanks. There is a small mistake in the way the time is formatted. The actual maths that figures out the hours/min/sec/ms is correct, it's just a mistake in the formatting.

If you change the method to look like this, it should work fine:

def GetTimeStr(self):
"""Get a string representing the time (

A string representing the time.

return '%d:%.2d:%.2d.%.3d' % (self.GetHours(), self.GetMinutes(),
self.GetSeconds(), self.GetMilliseconds())

I've fixed the bug in my version. I don't know when I will have time to test/release the next version, as it has a lot of changes.

Quote from DarkTimes :If you change the method to look like this, it should work fine:

sorry, it doesn't. the minutes contain always the full hours.
for example: 1h 20min 12.334sec -> 1:80:12.334

look at my code.

Ciao... paXton
Ah, you didn't mention what the bug was in your bug report. I looked at the code, saw a bug with the formatting, and presumed I'd fixed the one you were talking about.

Anyway, no biggie. I've added your fix to my version. Thanks for the help.

Here's some code:

def GetMinutes(self):
"""Get the time in minutes.

The minutes component of the time.

return int(math.floor(self.__ms / 1000 / 60) % 60)

def GetTimeStr(self):
"""Get a string representing the time (

A string representing the time.

return '%d.%.2d:%.2d.%.3d' % (self.GetHours(), self.GetMinutes(),
self.GetSeconds(), self.GetMilliseconds())

I am uploading a BETA of Pyinsim 0.2, which contains many changes to the library. It still requires some testing, so I am not designating it the official release just yet. When this comes out of beta, I will make this Pyinsim 1.0. You can download it at the bottom of this post. The existing pyinsim examples in this thread have not been updated, so please look at templates\ to see some code examples for 0.2/1.0RC.

Changes since 0.1.9:

Members Renamed:

In order to better comply with the Python style-guidelines, a great many methods, functions and variables have been renamed. The following rules have been applied:
  • Module, function and method names begin with lower-case character.
  • Class names are capitalised.
  • Members preceded by an underscore '_' indicate they are private to the module.
  • Members preceeded by double-underscore '__' indicate they are private to a class.
  • Members suffixed by an underscore '_' are named this way to prevent clashes with existing members (EG type_ or str_).
  • ALL-CAPS indicates the member is a constant.
Members Renamed Redux

In addition to this, several functions and methods have been generally renamed.
  • ToUnicode renamed strToUnicode
  • ToMps renamed speedToMps
  • ToKph renamed speedToKph
  • ToMph renamed speedToMph
  • LFSTime.GetHours renamed to LFSTime.hours
  • LFSTime.GetMinutes renamed to LFSTime.minutes
  • LFSTime.GetSeconds renamed to LFSTime.seconds
  • LFSTime.GetMilliseconds renamed to LFSTime.milliseconds
  • LFSTime.GetTotalMilliseconds renamed to LFSTime.totalMilliseconds
  • LFSTime.GetTimeStr renamed to LFSTime.timeStr.
  • InSim.ConnectionLost renamed to InSim.bindConnectionLost.
Further Changes to LFSTime class.

The method LFSTime.GetLapTimeStr has been removed, and now LFSTime.timeStr serves for both lap time and time strings. The signature for this method is:

str LFSTime.timeStr(bool hours=False)

Set hours=True to force use of the hours component of the time, which will otherwise be omitted unless hours > 0.

Changes to InSim.send()

The method InSim.send(data) has been renamed to InSim.sendB(data), which accomplishes the same thing. The send method is now a shorthand for sending packets, without having to create a seperate packet object first. For instance, what was previously:

insim.sendP(pyinsim.Packet(pyinsim.ISP_MST, Msg='Hello, world!'))

Has now been simplified to:

insim.send(pyinsim.ISP_MST, Msg='Hello, world!')

This is now the recommended way of sending packets, however previous usage of sendP still works as it did before.

Changes to InSim.bind()

InSim.Bind has been changed, it now no longer accepts a dictionary of event handlers, but a separate bind call must now be made for each one. For example, whereas before you did this:

insim.bind({ISP_VER: versionCheck, ISP_MSO: messageReceived})

You must now do:

insim.bind(ISP_VER, versionCheck)
insim.bind(ISP_MSO, messageReceived)

General Changes
  • Fixed bug in checkIP() function.
  • Fixed bug in LFSTime.timeStr() method.
  • Fixed bug in LFSTime.minutes() method.
  • Fixed bug in ISP_SMALL packet.
  • Removed keepAlive parameter from InSim constructor.
  • Added ISP_ALL packet type, which allows you to specify a single callback for all packet events.
  • Added bool InSim.isBound(type_=ISP_NONE) method, which returns True if an event has already been bound.
  • Added insim reference to connection lost callback.
  • Added bindThreadError(callback) method, which allows you to bind a callback to catch an error from the internal receive thread.
Pyinsim Template

The template has completely been rewritten, in order to comply with the many updates to the pyinsim module in this release. It is much better now.


The module documentation has been moved to the epydoc documentation generator, which provides much more comprehensive documentation than before. The whole documentation has also been revised, tweaked and brought up to date. The new documentation is a large improvement. You can access it by going to docs\index.html.


I was also wondering whether people would appreciate some examples of how to build a GUI application with Pyinsim?

Upload removed, see next post...
Uploaded version 0.2.1 BETA.

Changes since 0.2
  • Fixed bug with threadError event.
  • Some light optimisation of the internal receive thread.
  • Renamed the 'templates' folder to 'examples'.
  • More improvements to documentation.
  • pyinsim_template: General tweaks and refactoring.
  • pyinsim_template: Added threadError event handler and some useful debugging code.
Note: beta version removed, see first post for info.
Uploaded pyinsim 1.0 release to first post. It's no longer in beta.

Changes since 0.2.1 beta:
  • Added pack() method to _CarTrackPacket() class.
  • Added several new examples to /examples documentation folder
  • Lots of small internal tweaks.
Uploaded pyinsim 1.0.1 to the first post.

Changes since 1.0:
  • Lots of small internal changes, rewrote _Buffer class to further simplify InSim.__receiveThread, also changed the way in which blocks the calling thread, which should save a few CPU cycles.
  • InSim.connect() now checks that the socket is not already connected before attempting to connect.
  • strToUnicode() no longer removes colour codes from the string, set the new parameter cols=False to return to the previous functionality.
Thanks for the updates! At least i wont be bored tonight, my apps are still running at 0.1.9 version...
pyinsim 1.1 released!
Uploaded pyinsim 1.1 to the first post.

Changes since 1.0.1:
  • Added OutSim and OutGauge support.
  • You can now create multiple event-handlers for a single packet event.
  • You can now also bind multiple event-handlers to connectionLost and threadError events.
  • Added InSim.raisePacketEvent(packet) method, which is useful for testing and debugging.
  • Added optional name parameter to InSim constructor and InSim.getName() method, which is not used by pyinsim, but useful if you need to tell multiple connections apart.
  • Fixed syntax error bug in PSE_* flags.
OutSim and OutGauge

There are two new classes, named OutSim and OutGauge. They both work the same way (they inherit from the same base class internally) and have been designed to work as similarly to InSim as possible.

Here's a typically trivial example of using OutGauge, which checks the OG_SHIFTLIGHT flag, and prints out a message whenever the shift-light comes on. In order to enable OutGauge you must update your LFS cfg.txt file.

OutGauge Mode 0 :0-off 1-driving 2-driving+replay
OutGauge Delay 1 :minimum delay between packets (100ths of a sec)
OutGauge IP :IP address to send the UDP packet
OutGauge Port 0 :IP port
OutGauge ID 0 :if not zero, adds an identifier to the packet

Here is the example.

import pyinsim

def outgaugePacket(outgauge, packet):
if packet['Flags'] & pyinsim.OG_SHIFTLIGHT:
print 'Shift-light on!'

def timeout(outgauge, timeout):
print 'OutGauge timed out in %d seconds' % timeout

outgauge = pyinsim.OutGauge(timeout=20.0)

outgauge.connect('localhost', 30000)
except pyinsim.socket.error, err:
print 'OutGauge Error:', err

The timeout is new and important, as OutGauge uses UDP and UDP is stateless. It specifies the amount of seconds to wait for a response from LFS before timing out. If no response is received within the specified timespan, then a timeout event is raised and the connection is closed. Setting the timespan to zero will wait indefinitely. The default is 30.0 seconds.

There are a lot of changes and tweaks to the code, a lot of it has been completely rewritten, and a lot has been added. Goes without saying, it may have one or two bugs, but it all seems to work well in testing. I plan to work on some more stuff in the future, like receiving MCI and NLP packets on a separate UDP connection (which is technically possible at the moment, but looks messy), and I would also like to add some more advanced examples, such as using wxPython to create gauges for an OutGauge program and so on. But anyway, I hope it all works OK as it is for the moment.

As always, any comments, suggestions etc.. are welcome!
I was just looking through the recent demos for wxPython and saw this new one. It's like they were reading my mind.

This will make creating OutSim and OutGauge apps a lot easier.
Attached images