The online racing simulator
Searching in All forums
(921 results)
DarkTimes
S2 licensed
Quote from sicotange :
My explanations may be incomprehensible. You would understand the problem on sight if you try it out yourself on my server. If you want to we could meet for a few minutes on my server?

Yeah sure, I could join your server for a few minutes. I see you're online now, I guess I can join.

Quote :IS_CPP
=====

Concerning other packets, do you know an efficient way to force the shift+U view with the IS_CPP packet? I'm currently fiddling with it unsuccessfully.

You can do this by setting the ISS_SHIFT_U flag for the Flags property.

insim.Send(new IS_CPP {
Flags = StateFlags.ISS_SHIFTU,
});

The user can still exit Shift+U mode, you could watch for the STA event and switch it back on, although it might be better to just respect the users decision.
Last edited by DarkTimes, .
DarkTimes
S2 licensed
Something like that could be the cause of it. InSim.NET does not start receiving the next packet until the packet-handler for the previous packet returns. This means if that if your packet-hanlder method takes a long time, it can delay the processing of the next InSim packet. For this reason you should try and keep your packet-handlers as simple as possible.

You can demonstrate this very simply by adding an artificial delay to a packet-handler.

void AutoXMulti(InSim insim, IS_AXM axm) {
// Sleep thread for two seconds.
System.Threading.Thread.Sleep(2000);
}

If you had a packet-handler like this then the next InSim packet, of any type, would not be processed for two seconds. The whole packet receive thread would actually be slept in this example. The same is true of any long running operation that happens inside a packet-handler.

The alternative would be for InSim.NET to start processing the next packet in the stream before calling the packet-handler, but that would introduce the (likely) risk of multiple packet-handlers being called at the same time, which would mean serious multi-threading issues to deal with, as race conditions and deadlocks could occur as those handlers tried to access the same resources in your code.

It would depend of course on what you're actually doing, 100ms seems quite a long time for normal list processing. Are you doing any database or IO stuff as well? You can use a Stopwatch to measure the execution speed of your packet-handler, place a start call at the beginning of the method and a stop call at the end, then output the elapsed time.

void AutoXMulti(InSim insim, IS_AXM axm) {
Stopwatch sw = new Stopwatch();
sw.Start();

// Your AXM code here...

sw.Stop();
Debug.WriteLine("AXM elapsed time: " + sw.Elapsed);
}

This will give you the raw execution time of the method, as all the actual packet processing by InSim.NET is finished by this point.
DarkTimes
S2 licensed
Yes, you are correct about the issue with the password. There was a small bug that crept into the code for v2.0.14 that I have now fixed. I have uploaded a new version of 2.0.14 called InSim.NET 2.0.14b. Sorry about that!

I'm not sure what's going on with the IS_AXM packet, I will need to look into it and get back to you.

Edit: I've tested the AXM packet and I don't notice any delay when deleting packets. What sort of delay are we talking about? Is it a delay between you sending the request to delete the packet and the packet being deleted? Or is it a delay between when you delete an object in shift+u mode and the packet being received? Also are connected to a local copy of LFS when you notice the delay, or to a remote dedicated server?
Last edited by DarkTimes, .
DarkTimes
S2 licensed
I've uploaded InSim.NET 2.0.14 beta to CodePlex.

Changes:
  • Various improvements to InSim.Send() methods.
  • Fixed bug where OutSim and OutGauge IsConnected would throw an exception if no connection timeout was specified.
  • Unicode string encoding is now more strict (see above post).
There was a problem in previous versions where the InSim.Send(string) method would sometimes send an IS_MSX message packet instead of the smaller IS_MST. The logic has been updated so now the correct sized packet always gets sent. This can save bandwidth when sending large amounts of message packets.

In addition I also added a bunch of overloads for the InSim.Send(string) and InSim.Send(byte, byte, string) methods, to make passing a format string perform much better. For instance doing something like the following can perform faster than it did before.

// Send formatted string.
insim.Send("Hello, {0}", playerName);

Lastly, as mentioned above, the unicode string encoding has been updated to be more strict. This should alleviate some situations where InSim.NET would convert a unicode character to a close match instead of an exact match, for instance the Serbian character 'Ć' being interpreted as 'C' etc..

There may be some bugs, as I was messing around a lot with the string encoding code, so I've marked it as beta. Please let me know of any bugs or problems you have.

As always you can download InSim.NET from the CodePlex site.
Last edited by DarkTimes, .
DarkTimes
S2 licensed
Quote from DarkTimes :I've had a look at the encoding for those characters, it seems that .NET is happy to convert something like 'Ć' into a basic latin 'C'. I'm not sure what solution, if any, there is to this issue. Fact is that CP1252 encoding (the default) doesn't regard 'Ć' as an error, it just converts it to the closest match. I'm not sure if there is any way to make the encodings more strict about what they accept, which will cause InSim.NET to search the codepages for the correct character. 'Ć' is in CP1250.

I believe I've fixed this error. I have a new version of InSim.NET that includes this fix, as well as several code optimisations when sending messages. I'll try and release it as soon as I can.
DarkTimes
S2 licensed
I've been messing around some more with C# 5.0 and I'm getting my head around how this whole async stuff works. It's not as 'magical' as it first appears, which of course, nothing really is. One thing that bugged me when first trying out the new async library was that the basic Socket class didn't support it, instead you had to create a TcpClient and then get a NetworkStream from it. This isn't a big deal of course, but I would also quite liked to have had the async features available on the socket itself.

After messing around with the library for a while and doing a bit of disassembly I found a few helpful classes and methods that allow you to implement your own async code. The first one was the Task.Factory.FromAsync method, that provides a helper function for turning a traditional asynchronous begin/end operation into a task, and it's easy to wire this up to the Socket.BeginConnect and Socket.EndConnect methods.

I created a little Socket.ConnectAsync extension method:


<?php 
public static class SocketExtensionMethods {
    public static 
Task ConnectAsync(this Socket socketstring hostint port) {
        return 
Task.Factory.FromAsync<stringint>(
            
socket.BeginConnect
            
socket.EndConnect
            
host
            
port
            
null);
    }
}
?>

This allows you to now await the socket connect method, which is nice.


<?php 
async void SocketStuff
() {
    
Socket socket = new Socket(SocketType.StreamProtocolType.Tcp);

    
// Connect to socket asynchronously.
    
await socket.ConnectAsync("127.0.0.1"29999);
}
?>

The FromAsync method is really cool, but it only appears to support up to three generic type arguments, which mean it can't be used for stuff like Socket.BeginSend or Socket.BeingReceive. After a bit more poking around I discovered the TaskCompletionSouce class, which allows you to build your own Task. This allowed me to create SendAsync and ReceiveAsync extension methods.


<?php 
public static class SocketExtensionMethods {
    public static 
Task<intSendAsync(this Socket socketbyte[] bufferint offsetint sizeSocketFlags socketFlags) {
        
TaskCompletionSource<inttaskCompletionSource = new TaskCompletionSource<int>();
        
socket.BeginSend(bufferoffsetsizesocketFlagsar => {
            try {
                
taskCompletionSource.SetResult(socket.EndSend(ar));
            }
            catch (
Exception ex) {
                
taskCompletionSource.SetException(ex);
            }
        }, 
null);
        return 
taskCompletionSource.Task;
    }

    public static 
Task<intReceiveAsync(this Socket socketbyte[] bufferint offsetint sizeSocketFlags socketFlags) {
        
TaskCompletionSource<inttaskCompletionSource = new TaskCompletionSource<int>();
        
socket.BeginReceive(bufferoffsetsizesocketFlagsar => {
            try {
                
taskCompletionSource.SetResult(socket.EndReceive(ar));
            }
            catch (
Exception ex) {
                
taskCompletionSource.SetException(ex);
            }
        }, 
null);
        return 
taskCompletionSource.Task;
    }
}
?>

This allows you to await both send and receive operations.


<?php 
async void SocketStuff
() {
    
Socket socket = new Socket(SocketType.StreamProtocolType.Tcp);

    
// Connect to socket asynchronously.
    
await socket.ConnectAsync("127.0.0.1"29999);

    
// Send data asynchronously.
    
byte[] sendBuffer GetBufferToSend();
    
await socket.SendAsync(sendBuffer0sendBuffer.LengthSocketFlags.None);
    
    
// Receive data asynchronously.
    
byte[] receiveBuffer = new byte[1024];
    
int recevied await socket.ReceiveAsync(receiveBuffer0receiveBuffer.LengthSocketFlags.None);
    if (
received 0) {
        
// Handle data etc..
    

}
?>

So yeah, it seems pretty easy to knock together your own asynchronous socket code that supports the new await keyword. I may well create extension methods for all the asynchronous socket stuff, as it's actually not that complicated. I must say I've been really impressed with C# 5.0 so far, these are really lovely features which are going to make writing async code so much simpler in the future.
DarkTimes
S2 licensed
I'm still working on InSim.NET 3.0 but I think I will delay its release for a little while. With the Visual Studio 11 Beta just released I plan to make InSim.NET 3 target .NET 4.5. This makes a lot of sense as .NET 4.5 has big improvements to the asynchronous programming model, that would simplify the socket code in InSim.NET a lot. It would also allow changes to improve the overall API of the library. The plan is for InSim.NET 3.0 to be the last version of the library (except for smallish updates), so it makes the most sense to target .NET 4.5 in order to future-proof the code as much as possible.

I don't know when .NET 4.5 will be officially released, but obviously you can download Visual Studio 11 Beta right now.
Last edited by DarkTimes, .
DarkTimes
S2 licensed
Quote from martzz :Do I have to update python too to get the new version working?

Now my python is saying that:
Python 2.6.5 (r265:79063, Apr 16 2010, 13:09:56)
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.

Yes, the new version of pyinsim currently only supports Python 3.0. I don't know how it works on Linux, on Windows you can install Python 3.0 and Python 2.7 side-by-side. I will eventually back-port the new version to Python 2.7, but I don't know when exactly.

On Windows just install Python 3.0 and then rename 'c:\python32\python.exe' to 'c:\python32\python3.exe', then you can choose between Python versions by typing either 'python' or 'python3' at the command line.
DarkTimes
S2 licensed
Released InSimSniffer 1.3.0 Beta:
  • Added support for exporting and importing packets, using new .sniffer file format
  • Improved general packet performance
  • Improved packet filter (better UI and vastly optimized performance)
  • Can now sort list view controls (packets and details)
  • Added Help > Check for Updates menu item, to check if a more recent version of the program is available
  • Many small tweaks and fixes
As always you can download it from CodePlex. Please let me know of any bugs or problems you have.
DarkTimes
S2 licensed
OK - I hadn't thought about this before, but after some investigation I've figured it out. The problem is that you are copying the CompCar.X and CompCar.Y variables straight into the ObjectInfo.X and ObjectInfo.Y variables, but cars and objects in LFS represent their coordinates in different ways.

If you look in InSim.txt you see that the X and Y coords in CompCar are stored as 32bit ints and you need to divide them by 65536 to convert them into metres:

int X; // X map (65536 = 1 metre)
int Y; // Y map (65536 = 1 metre)

Whereas if you look at LYT.txt you see that the X and Y coords of ObjectInfos are stored as 16bit shorts which need to be divided by 16 to convert them into metres:

1 short 0 X : position (1 metre = 16)
1 short 2 Y : position (1 metre = 16)

So basically you need to first convert the CompCar X and Y coords to metres by dividing by 65536, then convert the metres to object coords by multiplying by 16.

In python code that would look like this:

# Convert car coords to metres
carXMetres = car.X / 65536
carYMetres = car.Y / 65536

# Convert metres to object coords
obj.X = carXMetres * 16
obj.Y = carYMetres * 16

# LFS expects the coords to be ints.
obj.X = int(obj.X)
obj.Y = int(obj.Y)

To incorporate them into your code example you could do something like this. Bare in mind that I've not tested this, but I think it should be correct.

def Place_cone(x, y, z, heading, UCID):
# Convert LFS coords to metres then convert the metres to
# object coords.
x = int((x / 65536) * 16)
y = int((y / 65536) * 16)

oi = pyinsim.ObjectInfo(x, y, 4, 0, 20, 0)
insim.send_packet(pyinsim.IS_AXM(UCID = UCID, PMOAction=1, Info=[oi]))
print('sent an axm')

def Multi_car_info(insim, MCI):
if MCI.ReqI == 17:
h = MCI.Info[0]
Place_cone(h.X, h.Y, h.Z, h.Heading, players[h.PLID].UCID)
print('sent packet')
else:
print('mci')

Hopefully that should work! Also, I hope that makes sense!

Edit: Note - you may also need to convert the heading, look at lyt.txt and insim.txt to see how to do that.
Last edited by DarkTimes, .
DarkTimes
S2 licensed
I had a bit of a brain wave today. Instead of storing the version info as a text file on some server somewhere, I could instead parse it from the RSS feed CodePlex provides for each project. As the RSS feed is generated automatically when I make a new release, this makes it much simpler to keep the latest version up to date. The code to do it is a little bit hacky, but it works. It's definitely better than editing and uploading a text file somewhere whenever I push out a new version.

I've been making lots of little tweaks to InSimSniffer over the last few weeks and I think I'll push out a new release soon. As always the latest changeset is on the CodePlex repository.
Last edited by DarkTimes, .
DarkTimes
S2 licensed
I started thinking about the timers and decided that I was handling them the wrong way. I realised the simplest thing to do was to just make them behave exactly like the existing Python threading.Timer class, except obviously with a different underlying implementation. I've changed it so that you now create timers exactly like you used to, except instead of creating a threading.Timer object, you create a pyinsim.Timer.

import pyinsim

# Function called when timer elapses.
def timer_elapsed():
print('Timer elapsed')

insim = pyinsim.insim_init('127.0.0.1', 29999, Admin='')

# Create a timer object set to elapse every 10 seconds.
timer = pyinsim.Timer(10.0, timer_elapsed, repeat=True)

# Start the timer.
timer.start()

pyinsim.run()

As you can see you just create a new instance of the pyinsim.Timer class and call start. You can also stop the timer by calling the pyinsim.Timer.stop() method. The Timer constructor allows you to set *args and **kwargs that get passed to the callback function as paramaters, just like the normal threading.Timer, so you can do stuff like this:


def timer_elapsed(arg1, arg2):
pass

timer = pyinsim.Timer(10.0, timer_elapsed, True, arg1='hello', arg2='world')
timer.start()

etc..

This seems like a much more sensible way to handle the timers than the way I was doing it before.

I've pushed these new changes onto the BitBucket repository.
Last edited by DarkTimes, .
DarkTimes
S2 licensed
Quote from jason_lfs :Hi. First thank you for all your efforts, Pyinsim is a great tool. Regarding pyinsim 3.0 and the automatic encoding. I often work with playernames that have latin characters like "ñ", "á", "é", etc. so I wonder if this automatic encode will affect me in any way.

It shouldn't affect you. All it means is that instead of strings containing mixed character encodings (separated by ^L, ^G etc..), all strings are now just unicode. In fact it should make handling strings in pyinsim simpler.

Quote :The timer is a cool feature as well. Currently I use a class that inherits Thread to create several objects than run processes as daemon threads. I found that I needed to be able to run once or repeat the process, pause it, kill it, pass arguments to the referred function (as a list), etc.

You can set the timers to run once or to repeat continuously, you can also stop timers, and pass them arguments. There is no way to pause a timer currently, I'll see about adding one.

You can set a timer to repeat by setting Repeat=True parameter. The timer function returns a timer object that you can use to stop the timer later. To stop a timer you need to call the timer_stop function with the timer obj as a parameter. This is something I will probably change in the future, as it's all a bit clunky.

# Store obj reference returned from method.
t = insim.timer(10, elapse_callback, repeat=True)

# Tell pyinsim to stop the timer.
pyinsim.timer_stop(t)

You can also pass arguments using the args parameter when creating a timer. These args get passed to the callback function when the timer elapses, along with a reference to the InSim object that the timer was set on.

def timer_elapsed(insim, arg1, arg2, arg3):
pass

# Set args to be passed to timer callback.
insim.timer(10.0, timer_elapsed, repeat=False, args=[arg1, arg2, arg3])

Right now the timers are a work in progress, as are most things in the library, so I will probably need to work on them some more before all the various uses are covered. I can already think of several problems with the way they are currently implemented that I will need to address.
DarkTimes
S2 licensed
Been working a little more on pyinsim 3.0.0 and I added non-threaded timers to the library, which is something I'd been meaning to add for a while. These are timers that get executed from the main packet handling loop, so you don't need to worry about any threading or synchronisation issues. This is a big help if you're trying to keep your program limited to a single thread.

Creating a timer is very simple.

import pyinsim

# Function called when the timer elapses.
def timer_elapsed(insim):
print('elapsed!')

insim = pyinsim.insim_init('127.0.0.1', 29999, Admin='')

# Set a timer to elapse once after 10 seconds.
insim.timer(10.0, timer_elapsed, repeat=False)

pyinsim.run()

Setting repeat to False causes the timer to elapse once and then dispose of itself, setting repeat to True causes the timer to keep elapsing until the connection is closed.

I use the select() timeout to handle the timers internally, which means that the timers will not start executing until after the call to pyinsim.run() has been made. It also meant that if you set a timer while the select function was already blocking, the timer wouldn't start executing until after the next packet had been received (and the select call unblocked). To get around this I made it so if you add a timer while select is blocking it will ping LFS (TINY_PING) to get some data sent back and make select return. It's pretty hacky but it seems to work. I can't find a way to force select to unblock, so until I find a neater way to handle things it will have to do.
Last edited by DarkTimes, .
DarkTimes
S2 licensed
outsim = new OutSim(1);

In this line you have only specified a 1 millisecond timeout, that's not long enough. You should specify a much greater timeout period such as a minute, or leave it blank so the connection never times out. You only need to call Connect once to tell it what host/port to listen for packets on, as I said above OutSim does not have a concept of being connected, it just listens for packets.

Anyway, this code works for me.

using System;
using InSimDotNet.Out;

class Program {
static void Main() {
new Program().mainLoop();
}

void mainLoop() {
LFS testfls = new LFS();

// Only need to call connect once.
testfls.Connect();

// Stop program from exiting...
Console.WriteLine("Press any key to exit...");
Console.ReadKey(true);
}
}

class LFS {
private OutSim outsim;
public float pitch = 0;

public LFS() {
// Leave timeout blank to stop program from ever timing out.
outsim = new OutSim();
outsim.PacketReceived += new EventHandler<OutSimEventArgs>(outsim_PacketReceived);
}

public void Connect() {
outsim.Connect("127.0.0.1", 30000);
}

void outsim_PacketReceived(object sender, OutSimEventArgs e) {
this.pitch = e.Pitch;

Console.WriteLine("OutSim packet received");
}
}

Last edited by DarkTimes, .
DarkTimes
S2 licensed
I'm not sure I understand what you're talking about, sorry.

OutSim and OutGauge use UDP which is a connectionless protocol. There is not really a concept of being connected or disconnected with UDP. There is no way to figure out if a UDP socket is connected or not, other than to check if you have received any data on the socket recently. If no data is received within the timeout you specify then the connection is closed. OutSim.IsConnected property returns true until the connection times out. If no timeout is set then the connection never times out and IsConnected is always true.

Maybe if you post some code showing what it is you're doing I can help you more specifically with your problem.
pyinsim 3.0
DarkTimes
S2 licensed
I've been working on pyinsim 3.0.0 recently, which is a new version of pyinsim designed to support Python 3.0. I decided to take this opportunity to fix a bunch of issues I had with the previous version of library, and also add some new features.

I'm not sure how/if I'm going to integrate the new version with the existing CodePlex repository, so in the mean time I created a new Mercurial repository on my BitBucket account. You can view, clone or download the development version of pyinsim 3.0.0 here:

https://bitbucket.org/alexmcbride/pyinsim

The biggest change to pyinsim, aside from some changes to the API, is that all strings are now unicode by default. pyinsim now automatically converts LFS encoded strings to unicode and back again when sending or receiving packets. In Python 3.0 all strings are unicode, and while I messed around with using the new bytes type to represent LFS encoded strings, this created a lot of issues and made programming pyinsim apps much more complex.

One of the primary goals of pyinsim is to be as simple to use as possible, so I took the decision to just make all strings unicode and do the encoding/decoding on the fly, (hopefully) without you noticing. Obviously this means that packing and unpacking packets is slightly slower than before, as each character in each string needs to be converted to the correct type, but in my tests any additional latency was barely noticeable.

Right now you can actually switch between unicode and ASCII strings (and even reimplement the string encoding/decoding stuff) by giving pyinsim a new StrFactory object. There are two default StrFactory objects in pyinsim, AsciiStrFactory and UniStrFactory, and you can change between them like this:
import pyinsim

# Set the string factory to ASCII.
pyinsim.str_factory = pyinsim.AsciiStrFactory()

# Set the string factory to Unicode.
pyinsim.str_factory = pyinsim.UniStrFactory()

# TODO: Write normal pyinsim code here.

By default the library uses the UniStrFactory() to handle strings, and this is intended to be the 'proper' way to handle strings from now on. You shouldn't need to think about all this, as I said it should work without you needing to worry about it. I have a few ideas for how to speed up the string conversions in the future, but right now I'm going with the simple way of doing things. All this StrFactory stuff is kinda interesting, but I don't know if I'll keep it around in the final version. I reminded of the quote about how any choice you give the consumer of your API is a choice you were unwilling to make yourself.

I have also made the API in general a little more verbose, as finally I think that a combination of succinctness and verbosity is the best balance. Too much of the former makes the library hard to understand, too much of the later makes it hard to program against. In pyinsim 2.0 I tried the make the API as succinct as possible, but in retrospect that was a mistake, and a lot of the functions ended up with confusing names. I have now changed how you init the InSim system, and also in how you bind events, as well as some other stuff in order to correct this.

Instead of explaining every change here is a quick example of some new pyinsim 3.0.0 code. This example is of a simple 'sniffer' style app, that dumps the contents of each packet received to the console (very useful for debugging).

#!/usr/bin/env python
#coding=utf-8

# Import pyinsim package.
import pyinsim

# Function called whenever a packet is received.
def packet(insim, pack):
# Dump packet contents to output.
print(vars(pack))

# Initialize InSim.
insim = pyinsim.insim_init('127.0.0.1', 29999, Admin='')

# Bind function callback for all packet events.
insim.bind_event(pyinsim.EVT_PACKET, packet)

# Send MST packet to LFS.
insim.send(pyinsim.ISP_MST, Msg='Hello, InSim!')

# Run the pyinsim event loop.
pyinsim.run()

As you can see the insim_init function is new, as well as the bind_event function (their related functions (e.g. outsim_init, bind_event etc..) have been renamed as well). Hopefully it should all be self-explanatory really, and you should look at the dev source code (mainly core.py and helper.py) to see the changes in full. I will of course try to document every change before the final version, but currently everything is still in flux. The library works much as it did before, it's just that some of the function and class names are slightly different. Better. Better?

There are countless improvements to the code overall, most of the library has been rewritten, and I've figured out better ways to handle lots of stuff such as the write/read socket code. Even though this new version of pyinsim does more (such as decoding unicode strings on the fly!), it is much more efficient in other areas. That being said, every change is also an opportunity for a new bug to creep in, so I anticipate lots of issues and errors to find.

Anyway, if you're an experienced pyinsim programmer, feel free to give it a try and come back to me with your comments and suggestions.

Thanks!
Last edited by DarkTimes, .
DarkTimes
S2 licensed
It works fine for me. I start LFS, WinAmper and WinAmp (any order is fine). In LFS I type '/insim 29999' and then I click Connect in WinAmper. Works perfectly.
DarkTimes
S2 licensed
MySQL provide an ADO.NET Driver for use with the .NET Framework. Probably the best thing to do would be to use a LINQ to MySQL provider, for which there are many options, such as Mindscape Lightspeed.

Using LINQ abstracts away the SQL code, so it becomes easy to change database solutions without having to rewrite all your queries, it also gives you compile-time type-checking of your queries as well, which can help prevent many bugs.

Far from being 'crap' .NET actually has a lot of good features that simplify database programming.
Last edited by DarkTimes, .
DarkTimes
S2 licensed
Quote from MadCatX :Well, you can't. I really didn't expect someone to use this on a host...

Always need to send a password if one is set in LFS, doesn't matter if it's a host or a local instance of the game.
DarkTimes
S2 licensed
I've not tried this, but I'd imagine you should start the Python program last, after LFS and Arduino are running. Otherwise the program might try to connect to LFS or Arduino before they are ready and cause an error.
DarkTimes
S2 licensed
Doing it reliably with WndProc messages is kinda hard, as it does need to run as a WinAmp plugin, but you can hack it together by finding the HWND of the WinAmp window, getting the window text and parsing what you need out. With Win32 you can do this with FindWindow and GetWindowText.

In C# you can just use the System.Diagnostics namespace.

using System.Diagnostics;

static string GetCurrentSongTitle() {
Process process = Process.GetProcessesByName("winamp").SingleOrDefault();
if (process != null) {
string title = process.MainWindowTitle;
if (!String.IsNullOrEmpty(title)) {
int index = title.LastIndexOf(" - ");
if (index > -1) {
return title.Substring(0, index);
}
}
return "Unknown song";
}
return "WinAmp not found";
}

DarkTimes
S2 licensed
Are you using the correct version of Python? That code was written for Python 2.6, so you will need to have either Python 2.6 or 2.7 installed to run it. From that error it looks like you're probably using Python 3.0, which is why it won't work. You can download Python 2.7 here.
DarkTimes
S2 licensed
The player's name is not included in the MCI packet, it's in the NPL packet that's sent when a new player joins the race. You need to keep your own list of players connected to the host in order to perform the lookup.

Here is a (very heavily commented) example that keeps track of all the connections and players on a host, and prints out the player's name whenever a MCI packet is received.

import pyinsim

# Store connections and players in dictionaries with their
# UCIDs and PLIDs as the keys.
connections = {}
players = {}

# Called whenever a host is joined.
def insim_multi(insim, ism):
# Request all connection packets are sent.
insim.send(pyinsim.ISP_TINY, ReqI=1, SubT=pyinsim.TINY_NCN)
# Request all player packets are sent.
insim.send(pyinsim.ISP_TINY, ReqI=1, SubT=pyinsim.TINY_NPL)

# Called when a connection joins the host.
def new_connection(insim, ncn):
# Add to connections dict.
connections[ncn.UCID] = ncn

# Called when a connection leaves the host.
def connection_leave(insim, cnl):
# Delete connection from dict.
del connections[cnl.UCID]

# Called when a player joins the race
def new_player(insim, npl):
# Add to players dict.
players[npl.PLID] = npl

# Called when a player leaves the race (spectate etc..)
def player_leave(insim, pll):
# Delete from players dict.
del players[pll.PLID]

# Called once every second with car info.
def multi_car_info(insim, mci):
# Loop through each car in the packet.
for info in mci.Info:
# Try get the player for this car (sometimes get MCI
# packet before all players have been received).
npl = players.get(info.PLID)
if npl:
# Print the player's name.
print npl.PName

# Initialize InSim.
insim = pyinsim.insim('127.0.0.1', 29999, Flags=pyinsim.ISF_MCI,
Interval=1000, Admin='')

# Bind packet events.
insim.bind(pyinsim.ISP_ISM, insim_multi)
insim.bind(pyinsim.ISP_NCN, new_connection)
insim.bind(pyinsim.ISP_CNL, connection_leave)
insim.bind(pyinsim.ISP_NPL, new_player)
insim.bind(pyinsim.ISP_PLL, player_leave)
insim.bind(pyinsim.ISP_MCI, multi_car_info)

# When first connected request current host info.
insim.send(pyinsim.ISP_TINY, ReqI=1, SubT=pyinsim.TINY_ISM)

# Run packet receive loop.
pyinsim.run()

DarkTimes
S2 licensed
Quote from martzz :I managed to get the hello insim program working. How could I now do almost the same program but that shows me coordinates that my car is. I should use MCI packet, but I don't know exactly how. :/ Could anyone help me.

I tried to change the MSTs to MCI but that didn't work. :S
Here is the original Hello insim program:

import pyinsim

# Initialize InSim.
insim = pyinsim.insim('127.0.0.1', 29999, Admin='password')

# Send message packet to LFS.
insim.send(pyinsim.ISP_MST, Msg='Hello, InSim!')

# Run pyinsim.
pyinsim.run()


Firstly you need to enable MCI updates when you create the InSim connection.

insim = pyinsim.insim('127.0.0.1', 29999, Flags=pyinsim.ISF_MCI,
Interval=1000, Admin='password')

This tells LFS to send MCI packets once every 1000 milliseconds (1 second). Next you need to give pyinsim a function to call when a MCI packet is received.

def multi_car_info(insim, mci):
for info in mci.Info:
print 'X: %d Y: %d Z: %d' % (info.X, info.Y, info.Z)

insim.bind(pyinsim.ISP_MCI, multi_car_info)

The MCI handler loops through each car in the packet and prints out its XYZ coords. The full example would be:

import pyinsim

def multi_car_info(insim, mci):
for info in mci.Info:
print 'X: %d Y: %d Z: %d' % (info.X, info.Y, info.Z)

insim = pyinsim.insim('127.0.0.1', 29999, Flags=pyinsim.ISF_MCI,
Interval=1000, Admin='password')

insim.bind(pyinsim.ISP_MCI, multi_car_info)

pyinsim.run()

FGED GREDG RDFGDR GSFDG