The online racing simulator
Python - pyinsim - A Python InSim Module
(243 posts, started )
Yeah I should have said "using Python as a".
Yeah, it's easy to log lap and split times, in fact I remember writing this exact program for someone a couple of years ago. The only issue is that LFS does not provide any way to figure out what setup someone is using, as that's considered cheating by the game. I can write a simple plugin that logs lap and splits for you though. Just tell me the format that the CSV file should use.
Quote from JustForFunRacing :Hmm.... would it possible to code something like that with Python/pyinsim:

http://www.lfsforum.net/showthread.php?t=70428

Here is a rough plugin I've written for pyinsim3000 that logs lap and split times to a text file. You need to drop it into the plugins directory and add 'plugins.lap_csv' to the PLUGINS variable in the config.py file.

It creates a new CSV file for each session (practice, qualifying, race etc..) and stores the CSV in the format:

username, nickname, track, car, lap_num, sp1, sp2, sp3, time

Obviously I've written it quickly, so it might have one or two bugs. You can stop and start the logging with the commands !start and !stop.

# lap_csv.py

import plugin
import datetime
import os

CURRENT_DIR = os.path.dirname(__file__)

# uname, pname, track, car, lap_num, sp1, sp2, sp3, time

class LapInfo(object):
def __init__(self):
self.splits = [0,0,0]
self.last_split = 0

class LapCSV(plugin.Plugin):
def __init__(self):
plugin.Plugin.__init__(self)
self.bind(plugin.ISP_RST, self.race_start)
self.bind(plugin.ISP_TINY, self.tiny)
self.bind(plugin.ISP_SPX, self.split)
self.bind(plugin.ISP_LAP, self.lap)
self.bind(plugin.ISP_MSO, self.message_out)

def connected(self, host):
host.send(plugin.ISP_TINY, ReqI=255, SubT=plugin.TINY_RST)

def disconnected(self, host):
if hasattr(host, 'logging') and host.logging:
host.file.close()
host.logging = False

def create_name(self, track):
now = datetime.datetime.now()
return '%s_%s.csv' % (track, now.strftime('%d_%m_%Y_%H_%M_%S'))

def race_start(self, host, rst):
if hasattr(host, 'logging') and host.logging:
host.file.close()
host.logging = False
name = self.create_name(rst.Track)
path = os.path.join(CURRENT_DIR, name)
host.file = open(path, 'w')
host.logging = True

def tiny(self, host, tiny):
if tiny.SubT == plugin.TINY_REN:
if hasattr(host, 'logging') and host.logging:
host.file.close()
host.logging = False

def split(self, host, spx):
npl = host.players[spx.PLID]
if not hasattr(npl, 'lap_info'):
npl.lap_info = LapInfo()
npl.lap_info.splits[spx.Split-1] = (spx.STime - npl.lap_info.last_split)
npl.lap_info.last_split = spx.STime

def lap(self, host, lap):
if hasattr(host, 'logging') and host.logging:
npl = host.players[lap.PLID]
if not hasattr(npl, 'lap_info'):
return
ncn = host.conns[npl.UCID]
sp1 = npl.lap_info.splits[0]
sp2 = npl.lap_info.splits[1]
sp3 = lap.LTime - npl.lap_info.last_split
host.file.write('%s,%s,%s,%s,%d,%s,%s,%s,%s\n' % (ncn.UName,
ncn.PName,
host.state.Track,
npl.CName,
lap.LapsDone,
plugin.timestr(sp1),
plugin.timestr(sp2),
plugin.timestr(sp3),
plugin.timestr(lap.LTime),))
npl.lap_info = LapInfo()

def message_out(self, host, mso):
if mso.UserType == plugin.MSO_PREFIX:
args = mso.Msg[mso.TextStart:].split()
if args:
cmd = args[0].lower()
if cmd == '!start':
if hasattr(host, 'logging'):
host.logging = True
host.sendm('^3| ^7Started logging', mso.UCID)
elif cmd == '!stop':
if hasattr(host, 'logging'):
host.logging = False
host.sendm('^3| ^7Stopped logging', mso.UCID)

Attached files
lap_csv.zip - 1 KB - 355 views
Color me impressed.
Quote from DarkTimes :OK, only one download in the past three days, I guess using a scripting language to control hosts isn't a popular idea.

Well, my problem is that I didn't(and still don't) understand what it is or what I could do with it.

But I certainly do like pyinsim and thank you very much for the library and the excellent examples (which is the only way an idiot like me can make a program). I used pyinsim to write a program that averages N number of past laps and keeps updating the average after each lap (moving average). It displays the result to the LFS chat screen for each driver. I wanted to duplicate the Time Trail mode from iRacing. It also writes the splits, laptimes, and averages to the Python shell window. Then I just copy and paste the results to a file after my session is over. Not very elegant but it works.

So thanks again and your hard work is appreciated even though we users don't always say so.
Great one, Dark Times!

I got it working, but there is one problem and two suggestion:

Problem: After ending the logging with the stop command and then closing your app, it takes quite a long time until the file is written completely (around a minute or so). I guess there is no "close file" command and Windows closes the file itself after a while.

Suggestion 1: Is it possible to only log my own times, instead of all connected racers?

Suggestion 2: Would it be possible to create an exe file of your app once it reaches final status?
If you want it as an .exe then it might just be easier to write it using .NET. You can make exe files from Python programs, but it's a pain the arse and usually not worth the hassel.

In terms of the other things, sure.
Hmm... well I tried to create an exe - without success. So .NET really seems to be the better choice.

I also saw, that you also have created Spark.... Hmm... Would take some days to learn how to code in .NET - but it´s worth it I guess...

Any clue how to solve the long waiting until the CSV is useable (it still stays a 0kb file for a long time)?
Quote from codehound :Well, my problem is that I didn't(and still don't) understand what it is or what I could do with it.

I've been thinking about how to answer this question for a couple of days, and I guess it does need an explanation.

Basically pyinsim 3000 is not an InSim library, it is a standalone InSim program that you extend by writing plugins.

The program itself is very basic. It manages multiple InSim hosts, keeps track of connection and players lists, plus a bunch of other things that almost every InSim program needs. It does not implement any functionality itself, instead you add functionality to it by adding plugins. Plugins are small, modular peices of code that can be easily 'plugged-in' to the main system by dropping them into the 'plugins' folder. You can write your own plugins, or use plugins that have been written by other people. This allows you to build a host system for your server just by choosing which plugins you want to add.

For instance, if you were building a lapper type server, there may be several plugins you could use. One for tracking lap times, another for storing laps in a database, another for awarding points to drivers, another for dealing with commands etc.. This way you can pick and choose which parts of the system you want to use, and can easily turn features on and off by adding and removing plugins. Ideally, each plugin would only do one small thing. You can think of them as small independent blocks you can combine in different ways to build exactly the program that you want. For instance if you didn't want your lapper server to award points to drivers, you could just turn that plugin off. Or if you wanted it to store driver points in a different way, you could switch that plugin out for a different one, or replace it with your own.

pyinsim 3k provides the infrastructure to support this. Ideally it should be usable by people without any programming skill, all they would need to know is how to add plugins to the system and configure them. Of course having the knowledge to write and edit Python code would be a benefit.

I need to write a proper post explaining how the plugins work, but I hoped people would figure that out by looking at the examples. Still, a more detailed explanation of how they work and why they work the way they do is required. Also it is just a rough, unfinished prototype. That said it is stable and most of the code is pretty good (which is why I released it, I was surprised by how much it didn't suck).
Quote from DarkTimes :I was surprised by how much it didn't suck.

I've been saying plugins are the way to go for the past 5 years, I'm so glad people are starting to take notice that programming for InSim is pretty hard when your new. Providing a good plugin interface is important for the prorogation of the game as a whole and will be a key feature to any fully functional InSim system and a key to increase the polarity of LFS as a whole.

We can do much better then this, we can do so much better then this, but it requires C/C++/(Source)PAWN and a hooks into the LFS core. Maybe in 5 years (S/P LFS S3) I'll write C++ InSimMod with some of Scawen's help in and SourcePAWN or regular PAWN for the plugins. Of course I'd need to teach myself much more about C++ then I already know, but I needed to know alot more about PHP before I could make PRISM and that's where the LFSWorldSDK came in handy.
I meant I was surprised that the code I had written didn't suck, I've been sold on the plugin idea for long time. I struggled quite a lot with the way the program was structured and it took me a long time for figure out the best route to go down. The thing I'm happiest about in pyinsim 3K is that it is not a multi-threaded program - it does everything on a single-thread. I plan to merge the new socket code back into the main pyinsim branch, as being able to create single-threaded pyinsim programs is a very important change.

That said I'm still trying to figure out whether to keep developing this. It am happy with it, but with PRISM getting so much support on the forum it seems unnecessary to have two plugin systems that are so similar. I do however have a rough prototype of a .NET plugin system that uses JavaScript as the language that I'm pretty excited about (it's more awesome than it sounds ), but it would be a colossal amount of work to finish.
Quote from DarkTimes :That said I'm still trying to figure out whether to keep developing this. It am happy with it, but with PRISM getting so much support on the forum it seems unnecessary to have two plugin systems that are so similar. I do however have a rough prototype of a .NET plugin system that uses JavaScript as the language that I'm pretty excited about (it's more awesome than it sounds ), but it would be a colossal amount of work to finish.

I think there is room for all three.
Quote from DarkTimes :I've been thinking about how to answer this question for a couple of days, and I guess it does need an explanation.

Basically pyinsim 3000 is not an InSim library, it is a standalone InSim program that you extend by writing plugins.


Thank you for your reply. Re-reading the post a third time it finally makes sense. Two things through me off. One, I was not clear that it was not part of pyinsim. And second, I missed the 'P' in "Plugin" and was reading it as though Plugin was plugin, referring to methods the user had to provide. :doh: Therefore, I was not seeing what advantages there were over just using pyinsim.
I was trying to create a project for this on Google Code, but it won't let me as there is already a InSim library on SourceForge called pyinsim, which is empty and looks discarded! Does anyone know anything about this? I checked the dates and it was register just after I posted the first version of the library. This is really annoying!

http://sourceforge.net/projects/pyinsim/

Edit: Pff now I've got to wait for this other guy to "approve" my bloody project!
OK, sod it. I've decided not to use Google Code but to use CodePlex instead, as really that's what I'm familiar with anyway. You can visit the new CodePlex site for pyinsim here:

http://pyinsim.codeplex.com/

I've done an initial commit for the pyinsim 2.0 source code, which you should be able to access. I'm almost ready to release pyinsim 2.0, but a couple of things still need to be worked on, such as the OutGauge and OutSim support which is currently very buggy. That said, InSim and InSim relay are currently fully supported and seem to be working well.

I decided to use Mercurial for this project, as I've been messing around with it for a couple of days and it seems really good. I have to say getting the CodePlex site setup literally took less than five minutes. And to commit the source code all it took was...

hg clone https://hg01.codeplex.com/pyinsim pyinsim
cd pyinsim
hg add
hg commit
hg push

which was awesome. Anyway, I'll provide more info about pyinsim 2.0 and why I've made a project site for it later.
-
(DarkTimes) DELETED by DarkTimes
I am trying to write a program that will detect when the connection to LFS insim dies and will restart my client program. I use the insim.close() command but I still get the following message when I try to init (still using 1.6 version of pyinsim, by the way):

InSim Error: A connect request was made on an already connected socket

def openConnection(insim, client):
# Initialise InSim.
try:
insim.init(client.clientAddr, client.port, Prefix='%', Admin=client.admin,IName=client.appName)
insim.send(pyinsim.ISP_TINY, ReqI=1, SubT=pyinsim.TINY_ISM)
onceConnected = insim.connected
except pyinsim.Error as err:
print 'InSim Error:', err

# Connect to LFS insim for first time.
onceConnected = False
openConnection(insim, thisClient)
while True:
try:
sleep(STATUS_CHECK_INTERVAL)
if not insim.connected:
if not onceConnected:
# This program started before LFS insim available, try again.
openConnection(insim, thisClient)
else:
# Connection to LFS insim was lost. Stop sockects and restart on next cycle.
insim.close()
onceConnected = False
except KeyboardInterrupt:
print 'User stopped program.'
exitProgram() # Close log files and save data. Then exit.

Edit: Sorry, I didn't realise this was the old thread. I don't provide support for this version of pyinsim anymore. If you really want to use it, you're on your own (the code is in site-packages if you want to read it). I suggest moving to the new and shiny version of the library.

Edit: I wrote a rough example of doing this with pyinsim 2.0.

http://www.lfsforum.net/showthread.php?p=1490842#post1490842

Python - pyinsim - A Python InSim Module
(243 posts, started )
FGED GREDG RDFGDR GSFDG