The online racing simulator
PoVo, to use this library I think you need to have a more proactive attitude towards programming.

First of all read the insim.h file, which contains the structs I use. It's the original insim.txt file in the "...\LFS\docs" folder converted to a header file. There you will find explanations on all packets and their fields, including buttons of course.

Then go to any of my examples and look in the main.cpp for code where button packets are created. That is, look for "ISP_BTN". If you don't understand what is going on there then please don't ask again about it, because all I'm using are functions included in standard C/C++ libraries and basic C/C++ features, and you should be able to understand all of that by yourself (or be able to look it up in any C++ reference manual yourself).
CInSim V0.5:

I updated the library with a bugfix and an important addition.

First of all, I thought I had made it so the send_packet() method was thread safe, but I forgot to add the most important lines. Basically I didn't lock/unlock the mutex var. I', sure I had done that, so I guess it was just a matter of distraction when it came to build the zip file of a work in progress...

Second, and most important, I finally added a function that sends variable sized buttons. Up until now you had to create a button with a 240 chars 'Text' field and it was sent completely using the send_packet() method, even if you didn't even fill the Text field with any text at all.

I recenlty came up with problems derived of network overhead so I decided to give it a go again. Turned out to be much simpler than I had anticipated. I guess I was ofuscated the other times I tried to sort this out...

The new function is called send_button() and must be used only to send buttons. The process is the same as before: you create an IS_BTN struct, and fill it with all the necessary data, and optionally you fill the Text field. Then you call the send_button() method just like you used send_packet() before. The new method calculates the text length, refills the Size field with the appropiate value -so you don't have to worry about knowing how long is your text beforehand- and sends only the necessary amount of data.

The IS_BTN that you create is always 240 chars long in the text field, but only the right amount of data is sent. This may mean an overhead for the insim regarding the amount of allocated memory used, but now there's no network overhead, which is more important. Anyway, the mentioned allocated memory overhead isn't very important because when you send many buttons yo usually reutilize the same IS_BTN struct time and time again, you don't create a new struct for each button

Soon I will be working on anti-flooding techniques of some sort to control that massive sending of buttons doesn't cause losing the TCP connection.
Quote from MaKaKaZo :Soon I will be working on anti-flooding techniques of some sort to control that massive sending of buttons doesn't cause losing the TCP connection.

When you do the test, it might be a good idea to have WireShark running so you can read raw TCP & UDP Packets, and get a better idea on what's sent and received by LFS and your clients.
#29 - PoVo
So I finally got everything working, and so far I'm enjoying this lib.

Just ran into a problem. I'm trying to make a players variable (int Distance) which holds the total driven distance in Metres.

So I took a bit of code from the C# LFS_External InSim app, to help me and this is what I got.

ginfo->players[i].Distance += (int)(((pack_mci->Info[j].Speed / 32768) * 100) / 2);

The problem is, this code is always 0. I don't exactly know if "+=" is the correct way of adding in C++, but the maths formulae should work.

Any Ideas?
Yeah, += is good in C++. No problems there.. But I do see a problem with the method of distance calculation. In the MCI packet, speed is meters per second.. Well, in order to get the distance you have to know how much time has passed. Which is what that 2 is I guess, 1 packet every 500ms? On top of that, the speed is variable between the 2 packets. Right? (I didn't work anything out, just theory )

For the 0, you have make sure its not integer division, which I think that is as speed is a word and the rest of it is whole numbers. I would copy speed into a float then do the math.. Also, check out C++ casts instead of plain C ones..

Instead of speed, another distance solution might be to use the X,Y,Z point and calculate the distance between the current and the last packet using something like:

xd = x2-x1
yd = y2-y1
zd = z2-z1
Distance = SquareRoot(xd*xd + yd*yd + zd*zd)

However this will also be an approximation as it will be a straight line between the points and not a curve like the driver may have taken. On a hairpin for example. In either case, the more points the better.

One final thing that might work is messing with the NLP packets. I'm not sure how the nodes work but if you know where they are and which node the driver is currently at, then you could get the distance between the nodes.

Hope this helps!
#31 - PoVo
Well the MCI packet is called every 1000 ms, so I actually don't exactly understand the formulae
-
(DarkTimes) DELETED by DarkTimes
Quote from PoVo :So I finally got everything working, and so far I'm enjoying this lib.

Just ran into a problem. I'm trying to make a players variable (int Distance) which holds the total driven distance in Metres.

So I took a bit of code from the C# LFS_External InSim app, to help me and this is what I got.

ginfo->players[i].Distance += (int)(((pack_mci->Info[j].Speed / 32768) * 100) / 2);

The problem is, this code is always 0. I don't exactly know if "+=" is the correct way of adding in C++, but the maths formulae should work.

Any Ideas?

Everything looks fine to me.

You look to be requesting MCI packets at a rate of 0.5 seconds (given the formula you are using). The Speed field in the CompCar struct is a 2-byte integer, and you are casting it to an (int), which should be 4-byte, bigger than the source data.

The operator += works in C++, so that is no problem either. The only way I see that the math would be 0 is in case that Speed is also 0. So I'd check first of all the value of the Speed you are grabbing. Maybe you are adding the speed from a wrong player?

I don't see any problem why this expression would evaluate as 0 any other than "pack_mci->Info[j].Speed" being zero.


EDIT: I hadn't read any of the previous replies... editing!

First of all, from "insim.txt":
word Speed; // speed (32768 = 100 m/s)

If you are requesting MCI packets at 1 second intervals, your math should be:
((pack_mci->Info[j].Speed / 32768) * 100)

But that would throw metres in x100, so unless you are going faster than 100 m/s it would evaluate as 0.

As Stuff said this is integer division you are doing, so to not lose precission you must change order:
((pack_mci->Info[j].Speed * 100) / 32768)

So the final code would be:
ginfo->players[i].Distance += (int)((pack_mci->Info[j].Speed * 100) / 32768) ;

By doing the multiplication first you might run out of range, but you are casting a (2-byte * 100) to a 4-byte, and that should be no problem I think.


Anyway, as it has been pointed out, this is no good way to calculate the amount of metres the car has moved, and the longer the period between MCI packets the lower the accuracy of the calculation, but if you don't need a lot of accuracy it is an approximation very fast to calculate.
#33 - PoVo
Quote from MaKaKaZo :So the final code would be:
ginfo->players[i].Distance += (int)((pack_mci->Info[j].Speed * 100) / 32768) ;


Thanks, that worked straight away!

So far I actually prefer this lib over LFS_External (C#) for language possibility reasons.

I was able to pick C++ up pretty quickly when I moved from C#, so I'm quite happy about it.

Currently I'm using your Event Control as a base, with CInsim 0.5
Actually the reason I chose C++ for this is because it's basically the only language I know, but the library is very basic and doesn't use C++ advanced features. In fact in my insim applications I use mostly C constructions like structs instead of classes, etc.


Good things:

- Whenever there is an insim update by Scawen the only thing you have to do to make CInsim work with the new changes is copy the "../LFS/docs/insim.txt" into your project as insim.h and edit the line for the ISP_BTN text field length (remove the comment).

- You can handle everything that insim sends to you and you can send anything that you want to insim, with no limitations.

- Being a "low level" C++ library, it is usually faster than other libs that provide high level functions and methods which in the end result in sentences being unnecessarily repeated.

- Using my basic tutorial applications as a base you can understand very quickly how this lib and insim work together and how to build your own application using a similar approach.


Bad things:

- Programming with this library is quite... "manual" not like other libs that provide high level functions. You have to build the whole packets with all the fields, but this is also maybe the fastest way when executing when it comes to reusing packets.

- If you need things like timers (for example to clear a button after X seconds) you have to get your hands on third party libraries to create and handle child threads. I use pthreads-w32 and it works pretty fine. It's used in "Event Control", which code is available so you can also have a look on how that works.

- My tutorial applications are not a good example of clean and neat code style. I pretty much do my whole applications all in only one .cpp file for the main and all the functions which handle all packets used in the application. Anyway, I'm not trying to teach people how to write programs with good style, but rather how to write insim apps using this lib!
Small update!

Quote :Changelog:

V0.51
  • Fix for the send_button() method. Now it's thread-safe, there was a small typo in one line.
  • The additional function mstrostr() has been renamed to ms2str() and now has an optional third parameter to indicate if the resulting string will contain hundredths of second (default) or thousandths of second.

#36 - PoVo
Hey, just another problem, what's the best way of displaying a Double variable on a button?

I need something like itoa();

Didn't really want to make a new thread, so I posted here
Quote from PoVo :Hey, just another problem, what's the best way of displaying a Double variable on a button?

I need something like itoa();

Didn't really want to make a new thread, so I posted here

Use the powerful "sprintf()" with the %f specifier:
http://www.cplusplus.com/reference/clibrary/cstdio/sprintf/

something like:

sprintf(pack_btn.Text, "Fuel burned: %f litres", ginfo->players[i].Fuel);

Would turn into: "Fuel burned: 123.23 litres"

See the example in the reference link above. You can add more text to the formatted.

sprintf is very useful to build preformatted C strings containing any kind of data: integers, C strings, floats, etc.
#38 - PoVo
Great! I tried it before, but never knew that I had to use the %.02f things.

I finally set up my KM display using %.03f, and it's very nice. At the moment I'm trying to set up a MySQL database, which is going well
New update!

Quote :Changelog:

V0.6
  • Added support for *NIX platforms. You only have to change in the insim.h file the "#define CIS_WINDOWS" preprocessor directive to CIS_LINUX, and you are ready to compile the lib under Linux/UNIX with the exact same functionality. (Portability code provided by MadCatX)
  • The additional function mstrostr() only uses ANSI-C functions now to ensure platform portability. All the occurrences of itoa() have been replaced by sprintf().

Ok, I have to be a complete noob and ask: How to get this to compile? It seems like pthread is causing me problems, cause it says "sched.h" not found or sth like that.

I visited their site(if that is it: http://sourceware.org/pthreads-win32/ ), but the download directories are htaccess protected with passes.. which I, obviously don't know. I saw that there are executables but, yeah, they are in those same download directories. So I'm kind of stuck.

Here's what I did to try compiling it:
Made an empty project in vc2010;
Added all the files to it, that I thought are neccessary;
That didn't work, so I removed all the files;
I then added all the files from the archive;
Got the same error;
Started browsing the net and chatting;
A day later, here I am, posting in this thread, after another few failed attempts.

I made so many empty projects to try different stuff, that I started giving them some stupid names like "damnit", "whattheduck", uncensored version of whattheduck too, "deletemeeeee" and the likes.

And please, don't judge my terminology, I know that it completely sucks.
Quote from broken :Ok, I have to be a complete noob and ask: How to get this to compile? It seems like pthread is causing me problems, cause it says "sched.h" not found or sth like that.

I visited their site(if that is it: http://sourceware.org/pthreads-win32/ ), but the download directories are htaccess protected with passes.. which I, obviously don't know. I saw that there are executables but, yeah, they are in those same download directories. So I'm kind of stuck.

Here's what I did to try compiling it:
Made an empty project in vc2010;
Added all the files to it, that I thought are neccessary;
That didn't work, so I removed all the files;
I then added all the files from the archive;
Got the same error;
Started browsing the net and chatting;
A day later, here I am, posting in this thread, after another few failed attempts.

I made so many empty projects to try different stuff, that I started giving them some stupid names like "damnit", "whattheduck", uncensored version of whattheduck too, "deletemeeeee" and the likes.

And please, don't judge my terminology, I know that it completely sucks.

Yes, it looks like I haven't been providing all the necessary files from pthreads-w32 to compile because I have them in my global includes path.

Anyway, you can download all the pre-built include and lib files from their sourceware ftp:
ftp://sourceware.org/pub/pthreads-win32/dll-latest/

You can also grab one of the compressed files which have everything, but the directory structure in those is kinda messed up.

I think you need basically the header files from the include directory (sched.h and maybe semaphore.h). The library files needed are both provided with the library (the ".a" and the ".dll").

If you have any further problem I'll try to help you, but I don't know about compiling with visual studio, I have never used it.

You have to add the CInSim files to the project, also link to the pthreads lib and, if required, to the winsocks2 lib. Then you will also have your own project files and headers, and you must have the pthreads DLL available in either a system DLL path or directly the working directory of your application executable.

You can download and try "Event Control" to check all the files needed (though the header files from pthread mentioned before are missing).
#42 - PoVo
Hey, I have gotten this to _kinda_ compile on Visual Studio. Only problem is I'm getting these errors:

1>------ Build started: Project: main, Configuration: Debug Win32 ------
1>CInsim.obj : error LNK2019: unresolved external symbol __imp__bind@12 referenced in function "public: int __thiscall CInsim::init(char *,unsigned short,char *,char *,struct IS_VER *,unsigned char,unsigned short,unsigned short,unsigned short)" (?init@CInsim@@QAEHPADG00PAUIS_VER@@EGGG@Z)
1>CInsim.obj : error LNK2019: unresolved external symbol __imp__connect@12 referenced in function "public: int __thiscall CInsim::init(char *,unsigned short,char *,char *,struct IS_VER *,unsigned char,unsigned short,unsigned short,unsigned short)" (?init@CInsim@@QAEHPADG00PAUIS_VER@@EGGG@Z)
1>CInsim.obj : error LNK2019: unresolved external symbol __imp__htons@4 referenced in function "public: int __thiscall CInsim::init(char *,unsigned short,char *,char *,struct IS_VER *,unsigned char,unsigned short,unsigned short,unsigned short)" (?init@CInsim@@QAEHPADG00PAUIS_VER@@EGGG@Z)
1>CInsim.obj : error LNK2019: unresolved external symbol __imp__inet_addr@4 referenced in function "public: int __thiscall CInsim::init(char *,unsigned short,char *,char *,struct IS_VER *,unsigned char,unsigned short,unsigned short,unsigned short)" (?init@CInsim@@QAEHPADG00PAUIS_VER@@EGGG@Z)
1>CInsim.obj : error LNK2019: unresolved external symbol __imp__gethostbyname@4 referenced in function "public: int __thiscall CInsim::init(char *,unsigned short,char *,char *,struct IS_VER *,unsigned char,unsigned short,unsigned short,unsigned short)" (?init@CInsim@@QAEHPADG00PAUIS_VER@@EGGG@Z)
1>CInsim.obj : error LNK2019: unresolved external symbol __imp__closesocket@4 referenced in function "public: int __thiscall CInsim::init(char *,unsigned short,char *,char *,struct IS_VER *,unsigned char,unsigned short,unsigned short,unsigned short)" (?init@CInsim@@QAEHPADG00PAUIS_VER@@EGGG@Z)
1>CInsim.obj : error LNK2019: unresolved external symbol __imp__socket@12 referenced in function "public: int __thiscall CInsim::init(char *,unsigned short,char *,char *,struct IS_VER *,unsigned char,unsigned short,unsigned short,unsigned short)" (?init@CInsim@@QAEHPADG00PAUIS_VER@@EGGG@Z)
1>CInsim.obj : error LNK2019: unresolved external symbol __imp__WSACleanup@0 referenced in function "public: int __thiscall CInsim::init(char *,unsigned short,char *,char *,struct IS_VER *,unsigned char,unsigned short,unsigned short,unsigned short)" (?init@CInsim@@QAEHPADG00PAUIS_VER@@EGGG@Z)
1>CInsim.obj : error LNK2019: unresolved external symbol __imp__WSAStartup@8 referenced in function "public: int __thiscall CInsim::init(char *,unsigned short,char *,char *,struct IS_VER *,unsigned char,unsigned short,unsigned short,unsigned short)" (?init@CInsim@@QAEHPADG00PAUIS_VER@@EGGG@Z)
1>CInsim.obj : error LNK2019: unresolved external symbol __imp__recv@16 referenced in function "public: int __thiscall CInsim::next_packet(void)" (?next_packet@CInsim@@QAEHXZ)
1>CInsim.obj : error LNK2019: unresolved external symbol ___WSAFDIsSet@8 referenced in function "public: int __thiscall CInsim::next_packet(void)" (?next_packet@CInsim@@QAEHXZ)
1>CInsim.obj : error LNK2019: unresolved external symbol __imp__select@20 referenced in function "public: int __thiscall CInsim::next_packet(void)" (?next_packet@CInsim@@QAEHXZ)
1>CInsim.obj : error LNK2019: unresolved external symbol __imp__send@16 referenced in function "public: int __thiscall CInsim::send_packet(void *)" (?send_packet@CInsim@@QAEHPAX@Z)
1>G:\Users\Povilas\Documents\Visual Studio 2010\Projects\main\Debug\main.exe : fatal error LNK1120: 13 unresolved externals
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

These errors require you to supply additional LIBS to the project in Visual Studio. I was getting more errors than this, but I solved it by adding the "libpthreadGC2.a" to the additional libs.

Seems like there is more missing. Any ideas? Is there any lib file or such for CInSim?

Thanks, Povo.
ws2_32.lib (WinSock2)
#44 - PoVo
Quote from morpha :ws2_32.lib (WinSock2)

Okay, thanks, I'll try it when I get back to my PC.

If it works I will post the source, for anyone else that needs it for VS.
#45 - PoVo
Hi, a few months back, I tried to get this library running with Visual Studio.

I got very far, to a point where the program builds, but crashes on start up.

I basically got the Event InSim app created my the OP, and copied it to the Project in VS.

I was unable to find the problem, so I decided to post it here, so that if anyone could have a look, to check what the problem is.

I would really appreciate someone experienced in C++ to look at my project (which can be downloaded from my site HERE (couldn't upload here as it's too big))

Thanks
I haven't had a chance to take a better look at the code yet, but I have the feeling the crash might have something to do with the pthread lib. You seem to be using pthreadGC2 library, but (AFAIK) the recommended version for use with MSVS is pthreadVC2.

EDIT: The code itself seems to be OK, I had to make few minor changes to get it compiled with GCC on my Linux box, but nothing that would cause a crash. I could connect to LFS and receive some packets, I didn't test your app any further though.
I did however replace the CInSim I found within your app with mine version, why did you replace all those strcpy with strcpy_s in ms2str function?
#47 - PoVo
Quote from MadCatX :I haven't had a chance to take a better look at the code yet, but I have the feeling the crash might have something to do with the pthread lib. You seem to be using pthreadGC2 library, but (AFAIK) the recommended version for use with MSVS is pthreadVC2.

EDIT: The code itself seems to be OK, I had to make few minor changes to get it compiled with GCC on my Linux box, but nothing that would cause a crash. I could connect to LFS and receive some packets, I didn't test your app any further though.
I did however replace the CInSim I found within your app with mine version, why did you replace all those strcpy with strcpy_s in ms2str function?

Because VS was giving me errors about "outdated" functions, and it wouldn't let me compile unless I changed it.

It said something like "Outdated function. Consider using 'strcpy_s'."

Would you be able to reupload the ZIP with the new stuff, so I could try it? Thanks
I'm quite sure VS can be overridden to stop bitching about "deprecated" strcpy so you don't have to rewrite the whole ms2str.

Check out this one if it works correctly...
Attached files
MyFailReloaded.zip - 77.9 KB - 590 views
I'm happy to see there's people at least doing something with my code

Sorry for not providing too much support on the lib. After the latest update some months ago I practically stopped visiting the forum as I'm on a LFS indefinite hiatus
#50 - PoVo
Quote from MadCatX :I'm quite sure VS can be overridden to stop bitching about "deprecated" strcpy so you don't have to rewrite the whole ms2str.

Check out this one if it works correctly...

Still no progress

1>------ Build started: Project: main, Configuration: Debug Win32 ------
1> main.cpp
1>g:\users\povilas\desktop\myfailreloaded\main\main.cpp(25): warning C4627: '#include "pthread.h"': skipped when looking for precompiled header use
1> Add directive to 'StdAfx.h' or rebuild precompiled header
1>g:\users\povilas\desktop\myfailreloaded\main\main.cpp(26): warning C4627: '#include "CInsim.h"': skipped when looking for precompiled header use
1> Add directive to 'StdAfx.h' or rebuild precompiled header
1>g:\users\povilas\desktop\myfailreloaded\main\main.cpp(757): fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add '#include "StdAfx.h"' to your source?
1> CInsim.cpp
1>g:\users\povilas\desktop\myfailreloaded\main\cinsim.cpp(37): warning C4627: '#include "CInsim.h"': skipped when looking for precompiled header use
1> Add directive to 'StdAfx.h' or rebuild precompiled header
1>g:\users\povilas\desktop\myfailreloaded\main\cinsim.cpp(791): fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add '#include "StdAfx.h"' to your source?
1> Generating Code...
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========


FGED GREDG RDFGDR GSFDG