The online racing simulator
Searching in All forums
(473 results)
MaKaKaZo
S2 licensed
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
MaKaKaZo
S2 licensed
Quote from Dygear :B compleaded the distance first, A compleated the distance, C only did half distance.

It does not matter that he was only four seconds away, it matters that he did not do an equal amount of distance to everyone else, he should be last because he did not do the same race distance as the people on the lead lap.

Extrapolate 2 laps / 1 lap, to 40 laps / 39 laps, so it's not "half the distance". The fact that A completed the distance does not mean that he should have completed it.

Let's say that driver B, the winner, completes all 40 laps in 40:00. Let's now say that driver A, with +45s penalty, completes 39 laps in 39:55. Then he completes 40 laps in 40:57, and we add +45 to this for a final total of 41:42.

If you had applied the +45s penalty on lap 39 instead of 40, the time for A at the end of lap 39 would have been 39:55 + 45 = 40:40. This means that he has taken longer to complete 39 laps (40:40) than what driver B took to complete 40 (40:00), which can be considered as "driver A finishes with 39 laps (+1 lap) with a total time of 40:40 (penalty included)".

I think that is the key, that you must apply the penalty at each lap and decide if the driver has already finished or not. That's what I'm going to do. When a player finishes a lap I check if he has a penalty and then compare his total time on the previous lap + penalty to the finishing time of the race winner.

I just woke up, I will think about it more later today.
MaKaKaZo
S2 licensed
The problem with players that don't finish the race is that they can join the track several times during one race and do some laps one time, some other laps another time and so on. It's hard for LFS to consider those players into the final results and that's why we only have results for players who actually finish the race.

I'm controlling this manually using LAP and RES packets. Every time a player completes a lap I store a result for him with his current info. Basically I build all the info contained in an IS_RES packet based on what I get from the IS_LAP. If the player enters pits, spectates or loses connection, his result is stored at that point and if he rejoins the track again he won't generate new results. This is the way I get results from everybody, even drivers who didn't complete a single lap.

I wrote a small InSim application called "CSV Generator" to generate CSV files with results for races and qualys and it's working quite well at the moment, but some situations are tricky. I was going to use LFS Stats CSV files but I didn't have enough info in them, so I wrote my own and made some fixes for drivers who rejoin track after having participated in the race (ie, "driver starts race -> driver disconnects -> driver reconnects -> driver joins track when race is over" would make him appear as "0 laps completed" in LFS Stats).
MaKaKaZo
S2 licensed
I don't like these situations, but of course they are rare. I gues I'll keep it the way LFS shows it.

I'm going to make a change to add drivers that have completed a certain percentage of the race length (in laps) as classified, which LFS does not. This implies re-sorting the original results in some cases. So I went ahead and thought about other cases that might lead to changing LFS' results because of other conditions.

One example of what I said above, from a FRL race:
http://www.funracingleague.com ... 2_race2_results_race.html

Let's say that the rule say "if a driver completes 90% of the number of laps (rounded down to the nearest whole number), he is considered as classified". Then, on this race in the example driver "[S-R] Pilu" in pos 29th with DNF and 19/20 laps completed (more than 90%), would move up to pos 27th, because he completed 19 laps in less time than "[Q3] nachogo27" and "yacomo87".

LFS doesn't consider drivers who haven't finished the race for the race results (which is a shame), and you can't either grab that info from the MPR replay header (it only contains info about finished drivers). I'm controlling that via insim, but in case the insim fails I want to have some tool to get info about players who participated in the race but didn't finish. I tried LFSStats CSV files but they contain too little info
Time addition penalties - LFS behaviour
MaKaKaZo
S2 licensed
While programming the modules that handle the race results for my league website I've come up with some unusual cases that I was curious about how LFS would deal with them. It's about time addition penalties.

The question is: how one driver with a time penalty compares to another one without any penalty but finishes a lap behind.


First test (prueba.mpr attached):

On a 3 laps race with mandatory pitstop, 2 drivers, the leader receives a +30 seconds penalty during his pitstop for speeding in the pitlane. This guy goes on and laps the other driver and finishes the 3 laps race length with his penalty (at this moment the "laps and laptime indicator" in the OSD turns orange). After him the other driver crosses the finish line with 2 laps and no penalty. What happens now? In this case it's quite confussing as the results table doesn't get filled. It only shows the first guy with the '?' in the position. The second driver who crossed the line doesn't appear, he crossed the line after the leader but didn't finish the race yet! This second driver must complete another lap, his third, and then LFS will generate the IS_RES packets for both drivers and sort them accordingly.

Results:
1st: the first guy who received the +30s penalty, with 3 laps and 3:25 total time (+30s added).
2nd: the other guy with no penalty, 3 laps and 3:52 total time.

I think this is OK, but confusing, because the second driver thinks he has finished when he crosses the line after the leader because the laps in the top right corner are orange. The truth is, given the leaders penalty, when he crosses the finish line LFS doesn't consider that the race has finished and so any other driver must complete the race length before comparing times.


Second test (prueba2.mpr attached):

This one is trickier! Now we have 3 cars and 2 laps (no pitstop). Driver A is issued a +45 seconds penalty by the admin (he could have made a jump start and the result would be the same). Driver B runs like hell and catches up to both A and C. When driver B finishes his second lap the order is this: A (+45s) -> B -> C. The time difference between A and C is about 4 seconds at this point. The race is won by B with 2 laps and 1:54 total time. After him C finishes in '?' pos with 1 lap and 1:57 (IS_RES pending for him). Driver A completes his second lap and finishes with 2 laps and 3:29 total time.

Results:
1st: B, 2 laps, 1:54 time.
2nd: A, 2 laps, 3:29 time (+45 added).
3rd: C, 1 lap, 1:57 time.

How does this look? Consider that drivers A and C were 4 seconds apart when B finished the race, with the difference that A was ahead of B and completed a second lap, and C was behind and finished with +1 lap.

If A had been lapped by B he had finished with +1 lap, and with the +45 seconds he would have gone 41 seconds behind C, final results being B -> C -> A.

If C hadn't been lapped by B, both A and C would have done the second lap, and probably the 4 seconds gap wouldn't have grown to more than 45 seconds in that lap. The final result would have been also B -> C -> A.

What happens here is that drivers are sorted first on the number of laps completed, and second on the time elapsed to complete those laps. Driver A has completed one more lap than C, and the +45s penalty doesn't mean any harm to him.

If it had been a stop&go instead of a +45s the thing would change, because at some point he would have needed to complete the penalty and the 4 seconds gap to C would have vanished. And there's no possibility to complete a stop&go on the last lap because you get automatically disqualified for that.



Any thoughts on this? I'm trying to make an automated system that handles penalties well, but I don't know what to do in these situations! What I do know is that I don't like these time addition penalties because they lead to weird consequences like the ones described
MaKaKaZo
S2 licensed
I have noticed that +45 seconds penalties appear in the html and CSV files as +30 seconds.
MaKaKaZo
S2 licensed
Quote from Dygear :That function expects a string in the LFS Format, it can't be UTF-8. The string should be left in the LFS format for the best results at all times.

Quite impossible given the settings of my database. At some point the single byte character string in cp1252 from LFS gets converted into UTF-8. The only way to avoid this that I found is to change the column charset to latin1 and to perform a "SET NAMES latin1" query before storing and retrieving the data and then do a "SET NAMES UTF-8" to change back. This is a big no-no, so I'm going to stick with my previous solution of using mb_convert_encondig() to encode the UTF-8 stored string into CP1252 before the parsing takes place.

I thought there was a problem with some characters, but turns out that I didn't have the asian charsets compatiblity pack installed in this Win XP box... just installed them and I see everything OK.

PS: Thx filur for the link, it provided good reference on the topic. I wish I could just do something in the "SELECT" statement that I use to retrieve these data to specify that I want the results in "latin1" without having to mess with connection variables. I tried with CONVERT but it didn't work.
MaKaKaZo
S2 licensed
OK, everything clear now. I'll think about some alternatives, like changing the collation setting of that field (which only contains text that comes directly from LFS) to latin1_general_ci (or the MySql collation setting equivalent to cp1252, if there's any). This way I won't have MySql convert the characters to a different charset when storing the text from LFS, but if my general setting is UTF-8 I will still need to convert to cp1252 after retrieving the data.

My knowledge on encoding systems and collation settings in MySql is rather limited, so I'll try to run some tests and read doc and see if I can get everything right.
MaKaKaZo
S2 licensed
My MySql collation settings are all set to UTF-8. All the tables are in UTF-8 and global collation setting is UTF-8 as well.

I really don't understand how encoding the string before storing it would change the result, and I wouldn't know how to encode "char *" C strings from my insim application to UTF-8. I wouldn't even know where to start on that...

What I have done is to add this line at the beginning of the function:

<?php 
$str 
mb_convert_encoding ($str'CP1252''UTF-8');
?>

That way the first thing I do is convert the string from UTF-8 to CP1252 and then I process it. This has supposed a step forward and the sample string I provided before now is converted successfully. I have tried other sample strings with rare characters from other codepages and some characters still won't show, but most of them do.

How nasty is my solution? I've thought that as long as all my data is stored in UTF-8 format and is retrieved in UTF-8 as well, I'd rather try to change the codepage_convert() function before trying other alternatives.
MaKaKaZo
S2 licensed
I'm having trouble converting text from LFS to HTML. I'm using the functions provided here in post #4 (I had to modify D34N0's function because it always adds an </span> at the end even if there's no color codes at all in the original string).

I don't really know what's happening, so I thought that maybe you guys can help me figure it out.

I'm saving text from LFS to a mysql table encoded in UTF-8, then I retrieve this text in PHP and show it on a UTF-8 encoded webpage. An example:

I save a player nickname, say "44# C.Mákaro" in all white. This is saved in my DB as "^744^h C.Mákaro".

Then I retrieve this nickname and I send it to HostToHTML to convert it to HTML. The problem comes in the function "codepage_convert()". I added a few debugging lines to it to see what was happening, and this is what I get:
Original: ^744^h C.Mákaro
^: 94
7: 55
4: 52
4: 52
#: 35
: 32
C: 67
.: 46
M: 77
�: 195
�: 161
k: 107
a: 97
r: 114
o: 111
Tmp: ^744# C.Mákaro
Converted: ^744# C.Mákaro

First is the original string as the function receives it, then the ASCII value of every individual character as in "ord($str{$i})", then the $tmp string just before mb_convert_encoding() and finally the resulting string.

First of all, the '^h' is converted to '#' in the beginning, which is allright, but then the 'á' is interpreted as two characters in the main loop? Why? But then the $tmp string which is passed to mb_convert_encoding() is ok again. But mb_convert_encoding() turns it into a wrong result...

Then again, if I skip the codepage conversion and use only "format_host_colours()" I get the 'á' character right, but I lose the # because '^h' gets stripped out of the string.

What is exactly happening? :-/
Last edited by MaKaKaZo, .
MaKaKaZo
S2 licensed
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).
MaKaKaZo
S2 licensed
New update!

Quote :Changelog:

v0.42
  • Now uses CInSim v0.6 (more stable and efficient).

MaKaKaZo
S2 licensed
New update!

Quote :Changelog:

v0.42
  • Now uses CInSim v0.6 (more stable and efficient).

MaKaKaZo
S2 licensed
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().

MaKaKaZo
S2 licensed
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.
MaKaKaZo
S2 licensed
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.

MaKaKaZo
S2 licensed
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!
MaKaKaZo
S2 licensed
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.
Last edited by MaKaKaZo, .
MaKaKaZo
S2 licensed
I don't mean to barge in this discussion, but a quick statement to say that there are several releases and I still don't know what PRISM is all about. All I know is that it's cool, it's written in PHP, and there will be plugins. Now that there's a subforum and all shouldn't there be somewhere a sticky to explain what this is all about? Like a FAQ or something.

This project sounds nice and I might be interested in writing things for this after I've finished my current C++ insim project, but I still don't get it! Please consider a post like "PRISM for dummies like makakazo" :-)
MaKaKaZo
S2 licensed
Cool! I'll be there and bring some other drivers too ;-)
MaKaKaZo
S2 licensed
Quote from Dygear :Give me a date and time and I'll show up to help you test out.

When I'm done with the user interface I'll post a public request for beta testers somewhere visible (probably in the programmers forum and somewhere else). But first I have to re-do some things, like help/rules/commands windows and add a couple of commands to show info about the next race and PB analysis compared to the best lap.
MaKaKaZo
S2 licensed
I believe it's a server<->client issue. My insim socket is a blocking one (which is by default), so I believe that if I did everything right my socket would have no problem handling this situation, as it can be blocked and wait in send and recv calls. I think WOULDBLOCK must be manually handled only when you use a nonblocking socket, in which case you are in charge of checking and controlling when you can send or receive data.

I have to say that I see that message in the LFS dedicated server console, I don't know if it also shows in the client's chat when they lose connection. The first time I saw the wouldblock message was when I was still using max sized buttons. When a client requested a table I would see first the wouldblock message and if he kept requesting more tables then I saw repeating green messages "TCP: Cleared emergency store". But actually during this test the client never lost connection to the server, and I was the only one seeing those messages in the server console.

After this I changed my insim library to trim button packets and reduce dramatically the network usage for these button-tables. With this change I no longer see "TCP: Cleared emergency store", but if the client goes crazy requesting buttons a wouldblock message may *or may not* appear and it comes with a client disconnection.

My concern right now is that I'm testing this right now with only two people online, and one of them is me, and I have all LFS client, LFS host and the insim application running on the same machine -though my connection is pretty poor in upload bandwidth!- I'm worried that disconnetions may occur more often in a crowded server.

Anyway, my insim and my dedicated server seem to survive pretty fine. I think I'll wait to do some testing in a *real* server hosted by some serious hosting company and have a bunch of people online requesting buttons and we'll see what happens!
MaKaKaZo
S2 licensed
Yes, this is what has finally brought me to send the buttons trimmed to avoid the overhead. A full table with max text width could mean about 252 bytes/button x 60 buttons = 15120 bytes! (14.7 KB for a single table!). Now a full table is at max 28 bytes/button x 60 buttons = 1680 bytes (1.64 KB).

That is sent in a single burst by the insim to the host, and then from the host to the client. I don't know how big the client connection TCP buffer is, but is sending 1.5 KB that much?
IS_BTN flooding control (TCP - wouldblock)
MaKaKaZo
S2 licensed
Hi folks!

I've come up with this problem when programming my insim application, the famous TCP - WOULDBLOCK.

After doing some research I've been reading some interesting old threads that discuss the topic. I'm no expert, so first of all I'd like to know what is exactly happening and what would be the best ways to tackle this problem. I'll explain first what is happening in detail.

My insim app is server oriented. It's a league managing insim. Players can request tables to see the TOP PBs and pre-qualifying times. Each table is at most 65 buttons, with not a lot of text.

Players can click on other players names in the tables to see a detail of their times, and each time they do that the table is cleared and completely re-sent.

So I'm testing with my teammates clicking on names like hell to force the insim to send a lot of buttons to them.

The server is located on my home computer, but it hangs on pretty well until at some point the server sends a TCP - WOULDBLOCK messsage and that player loses connection to the server.


As I understand it, what's happening is the following:
  • A player requests a table. The insim sends all the buttons to the server, and then the server sends the same buttons to the client.
  • If too much info is being sent to the client then the TCP buffer for that specific client's connection gets full and that sometimes causes the client to timeout or lose some important TCP packets that he should be receiving. This causes the client to lose connection.
Now I'm wondering some things... First of all, my friends have reported that they don't lose connection unless they are using any p2p or direct download software that is taking most of their bandwidth. Then again, my insim or the server never seem to die, they keep alive pretty nicely

Is it possible that the server might end up diying also because the insim is sending too many buttons to it? Which is the *best* way to prevent clients from getting their TCP buffer full?

What I want the most is help and ideas about how to avoid having people losing connection to the server. Any help would be appreciated on techniques to avoid this.
MaKaKaZo
S2 licensed
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.
FGED GREDG RDFGDR GSFDG