The online racing simulator
Guide: My first InSim Application
1
(34 posts, started )
Writing your first InSim application can be a bit daunting. This thread is designed to help you create your very first one, by providing a set of tutorials.

To those who have written InSim applications before, I hope that if you have time, and the language you use is not covered, or that you can improve or post alternative examples or tutorials, that you could pop together a tutorial for your chosen language and/or library.

What is InSim?
InSim itself is a protocol. A fixed method of talking to LFS. Think of it as a language, like French. There have been different versions (dialects) of InSim. Older versions maybe incompatible with the current version.

Take a programming language of your choice - any will do, as long as it can do some networking and there is some way for you to "pack" strings. Think of this programming language as a person.

You need to teach this "person" how to talk "french". How you do this would depend on the person. If this person natively spoke another language, like English, you'd teach them in the way they expect to be taught in an english school. Similiarly if they were spanish you'd use a spanish style of teaching.

What I'm trying to get at is that there's no correct way, in all cases, to create an InSim program. It depends on what you're using.

If you're using an interpreted language you can write the code, using whatever you want, and then run that code using the interpreter. For instance, you could write a PHP script, that understands how to talk to InSim, and then call it through the PHP command line interpreter.

If you were using a compiled language you'd write the code, using whatever you want, and then you'd need to compile that code so that you can run it.

InSim itself is not magic. All that InSim does, and can do, is inform a programmer how to get data out of LFS and how to put data back in.

Just to get slightly more complicated you can talk to InSim in 2 different ways - over TCP and UDP. TCP is "slower" but data from LFS is "guaranteed" to arrive whilst the connection is up, and will arrive at your program in a specific order. UDP is faster, but you will get no notification if LFS goes away, and the packets may arrive in any order. It is more common to use TCP than UDP these days.

However, at the end of the day every InSim application, whether or not the programmer knows it, makes the same decisions and goes through the same steps to acheive a connection to LFS using InSim and to maintain the connection. If you're using a third party library then you won't be exposed to much of the "hardcore" networking as the library will be taking care of it for you.

Vague synchronous workflow of an InSim client
In pseudocode it looks something like this:
Get data from user - address and port of client or server running InSim - usually localhost 29999
Make a connection to the given address and port
Send the ISI (InSim Initialisation) packet
Ask for the version to get sent (so that we can check that the thing we are connecting to is talking the same version of InSim)
Create a global buffer and a way of recording the buffer size (only necessary in some languages)
Start a receive loop - wait until we get data or until we are told to quit
Create a local temporary buffer
Copy any data in the global buffer into the local temporary buffer
We receive and append any data into the local temporary buffer
Clear global buffer
Create a local counter and set it to 0
Start a loop (we'll call this packet parsing loop), using the following logic: whilst local counter + next packet size <= local buffer size
Read the first byte of the rest of the buffer
Add this number to the local counter
Read and parse that number of bytes from the local buffer - this is a packet
Do whatever you want with the packet here - usually you'd want to send it to some bit of code to deal with it
Send any data you want back to LFS
Discard this packet from the buffer
When the packet parsing loop finishes, if any bytes remain copy them into the global buffer and size the global buffer size
When the receive loop ends clear the global buffer
Close the connection to LFS

If you have read the above and gotten a bit flustered, then do not worry as there are a few kind and clever people who have written a set of libraries which allow you to you concentrate on just writing your application and not worry too much about the above.

More information?
If you've chosen to write your own InSim connection and packet handler check out Insim.txt, included with all LFS distributions.

If you've chosen to use an existing library then the best starting point would be the documentation for that library.
-
C Tutorial (the_angry_angel) DELETED by the_angry_angel : Irrelevant
A good initiative, thank you TAA.

I think it's worth making clear as well, although you do mention it in your code comments, that you can find Scawen's own documentation for InSim in the InSim.txt file, which can be found in the LFS\docs directory. Of course it can be hard to decipher if you don't know C++ and you've never written a network application before.

If no one objects and someone else doesn't beat me to it, I will write an example InSim program for C# tomorrow evening after work. Of course, if someone else wants to do it first then please feel free.

BTW you can find out about Code::Blocks here, if you want to open TAA's project files for his C program. Be sure to download a nightly build and not the crappy age old release candidate though...



Edit: I still plan to make this, but I'm caught up in disaster recovery from spyware on this damn PC.
#3 - Beau
For all those who don't wish to use Code::Blocks. (eg. me who for reasons beyond my control, must use VC++ for a different project).
For VC++2008 Express. Do this to make it run.

Create an empty console application. Create the header/main files, and copy the code in.

IMPORTANT: it doesn't work if the file is named main.c. IT MUST be named main.cpp, It seems to be a bug(with VC++), but i was frustrated for 30 minutes figuring it out.

Then you need to link against the wsock32.lib.
To do this,

Project->Properties..
Configuartion Properties->Linker->Input-> Additional Dependencies
Put the path to wsock32.lib in there.

Now it should compile. Hooray. . Hopefully this helps people like me, who haven't learnt winsock programming, but just want to tinker.
C# Tutorial
I have written an example InSim program for C# and the .NET Framework, which is attached below as a Visual C# 2008 Express Edition solution.

The program itself is rather trivial, it's simply a console application that establishes a single TCP connection to InSim, checks the version and then responds to the InSim 'keep alive' packet. It should give you enough to get going with though. To expand it you would need to write more packets, as it currently only deals with the IS_ISI, IS_VER and IS_TINY ones.

This is not the only way to handle InSim with C#, it's not even really the best way, but I hope it conveys the basics of doing so in a fairly straight-forward manner. I considered using the System.Runtime.InteropServices to marshall the structs, but that's kind of an advanced topic, so I felt it better to demonstrate putting the packets together by simply building arrays of bytes. This is the way I learned to do it, so it should be easy enough to understand.

Most of the code is inside the Main method for simplicity, although each packet class is contained in a separate file. Also are also three files which contain the enumeration for the packet type, and the IS_TINY and IS_SMALL enumerations (although I might put these in one file, for simplicity).

The whole thing is heavily commented, both with code comments and C# XML style documentation, but if you have a problem with any of it please post here and I'll try to give you a hand. I have tested it a bit, but it probably will have one or two bugs. You know how it is.

All comments, questions, flames and death-threats welcome.

This code is released under the WTFPL license.
Attached files
InSimTutorial.zip - 12.1 KB - 1332 views
C++ tutorial (CInsim library)
I started using InSim with TAA C tutorial and built my own C++ library for using InSim. This library is now complete and I have written a couple of examples using it.

Although it's a library and stuff, it's still pretty basic, so it's more like a tutorial library than anything. Some people might want to give it a try and have a look at the examples provided. It is basic C++, just a simple class and the basics of InSim covered.

As I have already posted the files in other threads, I'll post just a link to the CInsim library thread, where you can find the links to both examples: http://www.lfsforum.net/showthread.php?t=47717
#6 - Etem
but ehm a readme is maybe good
Is it possible for one to make a PHP library?
Hi, thanks for that! Is it OK if I can talk to you abit more about this as I am kind of new with this LFS InSim. I am intermediate with PHP programming and I would like to get my head around these two technologies working together. May I add you to MSN or Yahoo or some other chat application?

Thanks
I would be a really terrible person to talk to about PHP, in fact, probably the worst person ever. Maybe Dygear or someone can talk with you about it.
Quote from DarkTimes :I would be a really terrible person to talk to about PHP, in fact, probably the worst person ever. Maybe Dygear or someone can talk with you about it.

LOL, what's that supposed to mean? Man that hurts.
I just meant that I hate PHP with a passion, so talking to me about it would be a mistake. You however as a popular proponent of the language, would be a much safer bet.

If you were to ask me how to make an InSim web app with PHP, I would tell you to install Django and pyinsim.
Quote from DarkTimes :I just meant that I hate PHP with a passion, so talking to me about it would be a mistake. You however as a popular proponent of the language, would be a much safer bet.

If you were to ask me how to make an InSim web app with PHP, I would tell you to install Django and pyinsim.

LOL, Oh, Ok. Yeah, I'll try and get some PHPInSim stuff done and get a package out soon, then I'll post some items building on that.
That will be cool Dygear. I have your InSim library and I basically don't know what to do with it. I am just learning and I thought I would learn by creating a connection first then maybe send a message to LFS and receive replies. I have your library (the connection) now I want to learn how to send and receive message and its this part where I have no clue where to start.

I added you on MSN if you have time to have a chat Dygear?
Quote from LifeSteala :That will be cool Dygear. I have your InSim library and I basically don't know what to do with it. I am just learning and I thought I would learn by creating a connection first then maybe send a message to LFS and receive replies. I have your library (the connection) now I want to learn how to send and receive message and its this part where I have no clue where to start.

I added you on MSN if you have time to have a chat Dygear?

I'm not a big MSN, AIM person. I don't even go on that for people I meet around where I live, so don't feel to bad. (Hell, I don't even go on it for girls ... I did one time, but that was a disaster ... well after a year relationship ... but I digress.)
Feel free to say 'bog off n00b' if you like, but I thought I'd share what I've learnt in the last few days.

This is for ABSOLUTE beginners to C#, and is FAR from complete.

I'm posting it in it's unfinished state because I don't want to finish it with total inaccuracies - so feel free to rip it to shreds - and when it's finished I'll add a thanks section on the end mentioning everyone who contributed

I'd have killed for a guide like this when I started - in fact, if anyone has a finished one I'd still love to have it
OMG Drew! I love you! Please keep going, this is going to help a lot of people! Well done.
For now - this is as far as I can go.

It's not quite finished - just a release candidate pending a few changes.

There will be a finished, polished version of this along with part 2 etc. as I acquire the necessary knowledge.

Could a few people who know this stuff please have a read through to make sure I'm not just talking crap?

It'd also be nice if you could point out anything obvious I've missed.

Thank you
Attached files
C#_n00b_guide.doc - 81.5 KB - 1102 views
-
(MariusMM) DELETED by MariusMM
Ta daaa!

But I don't know what's happened to the formatting....
Attached files
Document.txt - 18.5 KB - 817 views
Hey, wasn't sure where to post this, but someone asked me for an example of writing an OutGauge app in C++, and this is what I came up with. I'm posting it here in case it's useful to other people. Just note that I ain't a great C++ programmer, so there may be a few issues that I've not realised. Anyway it appears to work and shouldn't explode.

The code is a rehash of the pyinsim OutGauge example, which basically prints out a message whenever the shift-light comes on. I use this because it's simple, demonstrates everything you need to know, and is easily testable. It's usefulness, however, can be disputed.

Note: The OutGauge flags mask thing is explained in this thread.

#include <iostream>
#include <winsock2.h> // WinSock2 library (may need to add WS2_32.lib to project dependencies).

#define BUFFER_SIZE 512 // Receive buffer size (basically maximum packet size in UDP).
#define HOST "127.0.0.1" // Host to connect to.
#define PORT 30000 // Port to connect to the host through.

// Define types used by InSim.
typedef unsigned char byte;
typedef unsigned short word;
typedef struct
{
int X, Y, Z;
} Vec;
typedef struct
{
float X, Y, Z;
} Vector;

// Include InSim header.
#include "InSim.h"

void OutGaugePacketReceived(const OutGaugePack packet);

int main(int argc, char *argv[])
{

// Initialise WinSock version 2.2.
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
WSACleanup();
std::cerr << "Error: Failed to init WinSock" << std::endl;
return EXIT_FAILURE;
}

// Create UDP socket.
SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == INVALID_SOCKET)
{
WSACleanup();
std::cerr << "Error: Could not create socket." << std::endl;
return EXIT_FAILURE;
}

// Bind to receive UDP packets.
sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = inet_addr(HOST);
saddr.sin_port = htons(PORT);
if (bind(sock, (sockaddr *)&saddr, sizeof(sockaddr)) == SOCKET_ERROR)
{
closesocket(sock);
WSACleanup();
std::cerr << "Error: Could not connect to LFS" << std::endl;
return EXIT_FAILURE;
}

// Packet receive loop.
char recvbuf[BUFFER_SIZE];
memset(recvbuf, 0, sizeof(recvbuf)); // Set recvbuf to zero.
int bytes = 0;
do
{
bytes = recv(sock, recvbuf, BUFFER_SIZE, 0);
if (bytes > 0)
OutGaugePacketReceived((OutGaugePack &)recvbuf);
else if (bytes == 0)
std::cerr << "Error: Lost connection with LFS" << std::endl;
else
std::cerr << "Error: " << WSAGetLastError() << std::endl;
} while (bytes > 0);

// Cleanup and exit.
closesocket(sock);
WSACleanup();
return EXIT_SUCCESS;
}

void OutGaugePacketReceived(const OutGaugePack packet)
{
unsigned mask = 1 << DL_SHIFT;
if (packet.ShowLights & mask)
{
std::cout << "Shift light on!" << std::endl;
}
}

Neat, I might use that to create something.
Any reason why TAA's code is gone? I was hoping to use it as a base for a C interface with plugin support in PAWN. (Seeing as no one else seems to understand the power of the plugin interface provided by PAWN.)
No idea. I didn't delete it. I'm not sure if I've still got it to hand. When I'm back at my home office tomorrow I'll take a look and see.
Quote from the_angry_angel :No idea. I didn't delete it. I'm not sure if I've still got it to hand. When I'm back at my home office tomorrow I'll take a look and see.

Thank you. I wonder if the attachment got pruned.
Afraid I don't have it to hand any more - it isn't on any backup either so I most likely binned it months ago.

It's not exactly complex code tho and shouldn't take too long to write. Infact if you look at MaKaKaZo's CInSim and rip out the encasement in a class and convert it into inline you've pretty much got it with a few improvements.

Failing that it may even be a better idea to implement it using APR's buckets or something similar.
1

FGED GREDG RDFGDR GSFDG