The online racing simulator
Searching in All forums
(411 results)
MaKaKaZo
S2 licensed
Average movie, it wasn't worth downloading 100MB
MaKaKaZo
S2 licensed
Is there a script or something out there explaining what's going on? I still have to watch the first episode, but in this one I don't have a clue of what's happening most of the time XDDDDDD Anyway, I liked it!

Btw, I can do English with an Spanish accent
MaKaKaZo
S2 licensed
Quote from Dygear :MaKaKaZo, just wanted to thank you for making this available to the public, I really think it adds a lot the sim.

Scawen, read this and think of it as a possible future feature
MaKaKaZo
S2 licensed
Quote from Greenseed :Not sure i follow you... but if you wan to know if a driver is turning clockWise or not on a track, can be done with checking the y tangen angle from car x,y to 0,0 if you got : 51,52,53,54 mean i got clockwise if you got 54,53,52,51 mean counter clockWise. all track, Star/Stop are connected so work allways good, it just a way, i thought of some other.

Is that what you are looking for?

Easier than that would be to check if the nodes the car is in are increasing or decreasing, wouldn't it?
MaKaKaZo
S2 licensed
Quote from Scawen :Path nodes are approximately as long as 0.2 seconds of time when driving a car.

That is because the original path nodes are created by driving a car smoothly around the track, then connecting the resulting path as a loop. A path node is created 5 times per second, with the position and direction of the car.

But that depends which car was used, so that's why the 0.2 seconds is just a rough guide. Anyway this means the path nodes are more spread out at higher speed sections of track.

That's cool, in that case they can be used as a distance factor when you consider "regular racing". Maybe I'll use it for an InSim application that would be used during our destrcution derby-like team matches where wrong way driving, ramming and driving off track to avoid incoming cars is a must.

By the way... regarding nodes and our crazy game something just came up to me. We've been playing this game for a while now, and as I say wrong way driving is an essential technique. We play on AS2 and this is what happens:

While some people are driving to win the 3 laps race, others constantly go to pits and start directly exiting the pits in the wrong way (we use /cruise yes to avoid wrong way messages). When this happens in the first lap I think that the drivers that start from the pits to wrong way appear in the positions list as 1st, 2nd, etc. like they are leading the race, when they actually aren't as they went to pits and started wrong way.

I think this might be because everyone is noted as being on their first lap, but the guys going wrong way are in nodes higher than the ones that are racing for the win, so the game thinks they are leading. Can anyone confirm if that would be the reason?

I'm interested in this because in my InSim app I'd need to know who's the first driver of each team to make a GPS-like device that would tell team members how far (in nodes) they are to the other team leader, because in the minimap you see many "yellow cars" but you are never sure of who is the one you are aiming at. If you can't tell who's first in the first lap I'd start the tracking on the second, that's no problem, but I'd prefer it to start in the second.
Last edited by MaKaKaZo, .
MaKaKaZo
S2 licensed
Greenseed I've checked your code and I like your idea of using nodes, but in my example I just want to provide physical comparison relative to all cars present, not only the ones that are near you. So, if there are just two cars I don't care if they are really far away one from the other, I want the name of the closest one even if it's very far.

About the nodes idea... do all nodes have a similar length? For a in race usable application it would be nice to know.

I've seen in your code that your findNodeCars function repeats work all the time from previousNodeCount to nextNodeCount. I mean, it checks all cars at node previousNodeCount, then all cars again in previousNodeCount+1... and so on until nextNodeCount. Maybe you should do some change and do a simple loop that checks all cars just once, and if their node is within previousNodeCount to nextNodeCount then they're added to the List<CarMotion> carIds.

PS: I don't know C# but I think what I said makes sense
MaKaKaZo
S2 licensed
Quote from NiTRo_SvK :The ideal line could be disabled by turning on FCV (Forced cockpit view), but TC not...

I'm not sure about that...

PS: And the "4 key line" being ideal is highly questionable
MaKaKaZo
S2 licensed
Quote from dawesdust_12 :Kinda OT, but that Code::Blocks program seems to be very nice. Seems more versatile than Visual Studio. Nice find

What does OT mean?

Btw, I found Code::Blocks here in this forum, in TAA's C InSim tutorial.
C++ tutorial (CInsim library)
MaKaKaZo
S2 licensed
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
C++ - CInsim - A basic C++ InSim library (for Windows & UNIX/Linux)
MaKaKaZo
S2 licensed
Quote :Changelog:

UPDATE:
I haven't updated the library or been keeping track of InSim changes since January 2013. Forum member denis-takumi has created a repository on github.com that might be more stable and up to date than the files in this post. Check it at: https://github.com/turbosnail/cinsim

I have been off from LFS for a long time now and I'm not sure if I'll be back, but I receive email notifications of private messages and replys in this thread. I'll drop by to update whatever I can in the first post when I have time.

0.7 (Thanks to MadCatX for major improvements in this version)
  • Supports all new InSim changes introduced as of LFS 0.6C.
  • Updated send_packet(). It now properly handles both IS_BTN and IS_MTC packets and sends only the amount of data that is needed.
  • Removed send_button() as it is no longer needed (this breaks compatibility with old apps).
  • Simplified next_packet() and udp_next_packet().
  • Got rid of 100% CPU load caused by next_packet() on Linux systems by replacing select() for pselect() (other *NIX systems that use their own standard C library might exhibit a different behavior).
0.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 UNIX/Linux 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().
0.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.
0.5
  • New method called send_button(), used to send BTN packets of variable size. Up until now button packets were always 240 chars long in the text field, thus producing a big network overhead when a lot of buttons were sent. Now you have to create a button struct and fill it to your desire. The send_button method calculates the text length and only sends the appropiate amount of data. It also refills the 'Size' field of the struct based on the text length so you don't have to worry about that.
  • Fix for the thread-safe send_packet() method. Actually, it was supposed to have been updated in the V0.4 but it never was because I didn't add a couple of lines... Now it's suppossed to be working fine.
0.4
  • Now uses pthreads-w32 for thread-safe send_packet() method (several threads can use safely the send_packet() without overlapping). Before it had to be controlled by the application programmer.
0.31
  • Adds all changes done to insim as of LFS S2 0.5Z28
0.3
  • First stable version.

I started using InSim with TheAngryAngel C tutorial and built my own C++ library to use InSim. This library is now functional and stable. The library is called CInsim and it's meant for writing simple C++ InSim applications. It was originally written for Windows but UNIX/Linux portability was added in v0.6.

Most of the work must be done "manually". Creating and sending packets, multi-threading when needed and other stuff is responsability of the programmer. This library uses InSim as-is, and reading the insim documentation is a must when you have to manage packets.

What the library offers you is the basics of communicating with InSim:
  • Establishing the connection to InSim (full TCP, full UDP, TCP+UDP), and using all possible parameters accepted by InSim IS_ISI (initialization) packets.
  • Keeping the connection always alive.
  • Keeping the packets coming one at a time.
  • Peek the type of the next packet, so you know if you have to process it or skip it.
  • Return the contents of the next packet so you can process it (in case it was one of the types you wanted).
  • Send packets via the main connection (thread safe since v0.5).
  • Send size trimmed button packets via the main connection (thread safe since v0.51)
  • Close connection to InSim.
  • There's also a function to convert miliseconds to a C string (this is an independent function).
You must cast the contents of the packets to a certain InSim packet struct to access the fileds. This is shown in the working examples linked below.


EXAMPLES:

Note1: Some of these examples don't use the latest version of CInsim, so if you are going to work on your own project, be sure to grab the latest version in this thread.

Note2: These examples might use functions that aren't ANSI-C defined, so maybe you won't be able to compile them right away under UNIX/Linux, sorry.

I have posted three examples using this library, so I'll link to them instead of uploading the same files again:

CInSim V0.7:
  • Event Control: (Note: This was previously released using CInsim 0.6, but has since been updated to 0.7) This application is an event manager (it's server oriented). It was originally designed to enforce HARDCORE qualify sessions, in which the use of Shift+P and Shift+S is forbidden, so people can only do realistic pitstops. The current version allows the use of Race Directors, appointed by adding their lfs usernames in a text file, who can do more stuff to manage an event (restarting, ending, auto-reversing top grid drivers, director chat messages, etc.). http://www.lfsforum.net/showthread.php?p=1403034
CInSim V0.3:
  • LFS Session Timing: This application shows sector times and time differences to the session best when you cross a checkpoint. It uses buttons, independent threads for button timers and some interesting stuff. http://www.lfsforum.net/showthread.php?t=46643
  • X-Y-Z Positioning: This application shows the coordinates of your car and the name of the closest player to your position. Of course, more than one car must be online for a name to show up! It uses TCP for main connection and UDP for MCI packets.http://www.lfsforum.net/showthread.php?t=47675
The examples use the CInsim library (of course) and already come zipped with all the required files to compile and even an executable if you can't compile them. Also, code::blocks project files are provided for each example.
Last edited by MaKaKaZo, . Reason : updated version
MaKaKaZo
S2 licensed
Quote from the_angry_angel :The thread is open, so there's nothing stopping you from posting in it?

I'm very respectful and always ask for permission before intruding into a sticky I'll post both apps later.
C++ / X-Y-Z Positioning (application/tutorial)
MaKaKaZo
S2 licensed
SMALL UPDATE (2008-08-29):

The CInsim library was replaced with a newer version.


X-Y-Z POSITIONING v0.1

This is another application/tutorial I've written in basic C/C++ using my "CInsim" library. This time I have updated the library to support InSim TCP+UDP connection. The previous application I made can be found here: http://www.lfsforum.net/showthread.php?t=46643

All the source code is provided, of course, as well as a code::blocks project file

This application retrieves MCI packets every second and shows to each player his coordinates and the closest car at any moment while they are on track.

It provides a lot of information through the console so it's nice if you want to know what is happening and what packets are being received/what actions are being taken.


QUICK START

Just run the executable in the zip with 3 arguments: IP PORT ADMIN_PASS
(The PThreads dll must be in the same directory)

I recommend to create a Windows link and add those arguments in the properties.

Connect to the server and a welcome message should appear. You can be in the server when the application starts, but be warned that the first thing it does is end the current race/session.

Start running!


PS: I'd like these small apps I'm doing to be linked somewhere in the "My first InSim Application" thread or something like that.
Last edited by MaKaKaZo, .
MaKaKaZo
S2 licensed
Quote from bukhem :Hi.

I currently wonder how I can get a list of players that is currently connected.
I'm writing a small app that keeps track of lap and split times and therefor would need a list of existing players when it connects to the LFS-Client.

Thanks for your help.

Greetings.

This is a generic answer, not JInSim specific. As stated in the insim documentation, at any time you can request info about all connections and players sending an IS_TINY, with the following values (marked in red) in the field SubT:

enum // the fourth byte of IS_TINY packets is one of these
{
TINY_NONE, // 0 : see "maintaining the connection"
TINY_VER, // 1 - info request : get version
TINY_CLOSE, // 2 - instruction : close insim
TINY_PING, // 3 - ping request : external progam requesting a reply
TINY_REPLY, // 4 - ping reply : reply to a ping request
TINY_VTC, // 5 - info : vote cancelled
TINY_SCP, // 6 - info request : send camera pos
TINY_SST, // 7 - info request : send state info
TINY_GTH, // 8 - info request : get time in hundredths (i.e. SMALL_RTP)
TINY_MPE, // 9 - info : multi player end
TINY_ISM, // 10 - info request : get multiplayer info (i.e. ISP_ISM)
TINY_REN, // 11 - info : race end (return to game setup screen)
TINY_CLR, // 12 - info : all players cleared from race
[COLOR=Red] TINY_NCN, // 13 - info : get all connections
TINY_NPL, // 14 - info : get all players[/COLOR]
TINY_RES, // 15 - info : get all results
TINY_NLP, // 16 - info request : send an IS_NLP
TINY_MCI, // 17 - info request : send an IS_MCI
TINY_REO, // 18 - info request : send an IS_REO
TINY_RST, // 19 - info request : send an IS_RST
TINY_AXI, // 20 - info request : send an IS_AXI
TINY_AXC, // 21 - info : autocross cleared
};

With TINY_NCN the server will send an IS_NCN packet for each of the connections present (UCIDs).

With TINY_NPL the server will send an IS_NPL packet for each of the players present (PLIDs).

If you are keeping track of both connection IDs and players IDs (you should), you must do both.
MaKaKaZo
S2 licensed
Quote from Dygear :Splits in AutoX do generate SPX packets.

Then what SecondSkin is asking can be done. The thing is that he would need to give an accurate description of what he wants and how he's planning to use it, then maybe someone can pick the project.
MaKaKaZo
S2 licensed
Quote from SecondSkin :Posted this on the autox forum, but didn't get any response. Thought I'd try it here:

Is there any way to add minimum speed to autocross checkpoints (on any track), like is done in the LFS training modules? In the braking module, for instance, you can complete the course but you get a warning that your speed was too low and your time doesn't count. Is there any way to do this with a standard autox layout?

I guess this can be done with an InSim application. I don't know how autox checkpoints work... are they like normal track sector checkpoints? If so there's the chance that when a player crosses an autox checkpoint an IS_SPX packet might be sent. If that's the case then you can request an IS_MCI in which you can check the speed at that checkpoint.

There's also the possibility to check the speed at all times requesting MCI packets every second or so. If SPX packets are sent at checkpoints like I say above, then you can even set different minimum speeds for each sector of the layout.
MaKaKaZo
S2 licensed
Quote from Dygear :Learn something new everyday Thanks for that . So I take it that if there was only one car on track, then you would get one MCI packet, with the info value of 192? And while this information will give the ammout of players in the MCI packet, it will not give you the overall players. (Correct?)


<?php 
if ($MCI[0]->ComCar[0]->Info CCI_FIRST CCI_LAST AND $MCI[0]->ComCar[0]->Position != 1) {
    
# There is only one player in the race, and that driver is not first!
    # EPIC ERROR: PACKET ERROR, InSim ERROR, OR PROGRAM ERROR!
}
?>


Well, it gives enough info to know when a sequence starts and ends I didn't know about that either.


Good news guys: I managed to solve the UDP problem. As I thought it was a newbie mistake and some nice guy at www.codeguru.com helped me out checking my code.

The problem was that I wasn't binding the UDP socket to my local port. I mean, I specified that I wanted to use udpport 60000 and the server was sending packets to that port, but I never told my socket to listen on THAT port. I only told it to listen for incoming packets from IP x.x.x.x and port yyyy (the server's insim port).

So, when I use connect on the UDP socket without binding it previously to any specific port, it prepares a random port assuming that I'm going to start the communication (which I'm not). So, if I want to listen on a specific port I have to bind the socket first to my IP and port 60000 (the one I selected), and then use "connect()". That way my socket is prepared to listen on the desired port and not a random one.

I know most of you don't give a damn, but maybe someone that reads this will find it useful in the future. I'll be posting some example on car coordinates via UDP probably next week.
MaKaKaZo
S2 licensed
I'm trying now in a whats looks to be a nice forum for coders. If I get to solve it I'll post what was failing so people can laugh at my *probably* stupid mistake
MaKaKaZo
S2 licensed
Just forget the racism stuff and play the game, stop the racism discussion now please.
MaKaKaZo
S2 licensed
Would a name like "destruction checkers" fit better? The colours are already chosen and I don't know other words for white and black that are not racist. It's game made up by some spanish guy and I'm sure that he wasn't thinking about "negro" having racist connotations in English. I wasn't either when I posted the thread. Actually I've tried to change people's mind to make blacks->reds because black cars are harder to spot in the distance, but people still prefer black because they're opposite colors ans it's like checkers.
MaKaKaZo
S2 licensed
Dudes it's Spanish and we are talking about CARS!!!

Blancos = coches blancos (white cars)
Negros = coches negros (black cars)

There's no need to look for controversy in every word and less when it's a foreign language.

Btw, I've been on the black team every time because I like the black car better and I'm a winning streak, undefeated yet so... NEGROS FTW!!!

In Spain there's a much higher chance that people wouldn't want to be in the "blancos" team because it's Real Madrid (soccer team) color and there're a lot of Barcelona supporters that don't stand "being white", rather than people not wanting to be in the "negros" team for racism issues.
Last edited by MaKaKaZo, .
Blacks VS Whites (destruction derby-like team battles)
MaKaKaZo
S2 licensed
Hi guys! We've playing this blacks vs whites game for a couple of days now and just wanted to share the idea with all the community as it's a hell of fun!

First of all, this is not about a new "crash everyone server" or anything like that. We're a bunch of racers that just finished the current league season and right now we are spending some time fooling around to break with the training/racing routine.

The game is played between two teams with like 4 to 8 players each: blacks and whites. Whites use white car/white nickname, and blacks use black car/red nickname (black nicknames are harder to read).


The server is set to:

- Cruise ON (wrong way is a must).
- Small track (around 1 minute per lap).
- A few laps (3 or 4).


The only rule is: the team that gets a car to complete all laps win a point. The only thing that matters is who wins the race. Everything is allowed: speeding on pits, skipping the starting lights... everything!

When a team wins they add it to their score at the end of their nicknames (just to keep track of the score). A score limit is set so the first team to reach that score wins.

The use of TS/ventrilo is strongly recommended but you can play without it if you master the basic strategies.

Basic strategies are learnt quickly after some rounds, like quickly going to pits and rejoining when the other team runners are about to start a new lap so you catch with them as you exit the pits and then you have a good attack chance at the first corner. There're tons of tricks.

We don't prepare team beforehand unless there are majority of people from one team and they have their own TS server. Usually people randomly connect and join the team with less drivers/less points to have teams as balanced as possible.

I attach a replay of today's last round. The race is pretty lame in the beginning as blacks start pretty bad. As you guess there's no driving skill needed to play this, most of the time you don't need/shouldn't follow a proper line. But most of all... you are really not going to give a damn about driving properly

The awesome highlight of that replay is the last lap, as whites have three guys on lap, aiming to finish and blacks have only one but far away in the back. The rest of the blacks perform an amazing defense crushing all three white cars in the last corner/straight and they manage to win.

Believe me, this game is a lot of fun. I'm not a cruiser or a drifter, I'm a good old hotlapper/racer, but every once in a while these kind of games are really fun.
Last edited by MaKaKaZo, .
MaKaKaZo
S2 licensed
Quote from Dygear :InSim.txt Patch Z
struct IS_MCI // Multi Car Info - if more than 8 in race then more than one of these is sent
{
byte Size; // [B]4 + [U]NumP[/U] * 28[/B]
byte Type; // ISP_MCI
byte ReqI; // 0 unless this is a reply to an TINY_MCI request
byte NumC; // number of valid CompCar structs in this packet

CompCar Info[8]; // car info for each player, 1 to 8 of these (NumC)
};

I am guessing that's an error, meant to say NumC. But, with the MCI packets by them selves there is no way to find the amount of players in the race just by using the MCI packet. The only information it will give is the number of CompCar structs in the packet. So you will not know if you still have more coming. (Unless the number is less then eight of course, then that's the last packet, for the sequence.)

That's an interesting point. I haven't checked, but if it's really NumP as in all the players, then you don't know the size of that packet if there are more than 8 players. If it's to mean NumC then there's the possibility that the number of players is a multiple of 8 and you won't know which packet is the last of the sequence.

Anyway, you can always track the number of players connected at any given time so you wouldn't have problems. But that's right, you'd have to use more logic than just the info provided in the MCI packets.

Subliminal PS: Someone help me with the UDP stuff XDDD
MaKaKaZo
S2 licensed
Quote from the_angry_angel :UDP is sent a packet at a time, so unlike TCP (which is a stream) you don't have to worry about having partial packets, and having to have a global buffer, etc.

Totally right, hadn't thought about that. BUT, now that I think about it... if there's more than 8 people driving then multiple IS_MCI packets are sent "at the same time". That would cause problems, wouldn't it?
Last edited by MaKaKaZo, .
MaKaKaZo
S2 licensed
After some more testing, sniffing and stuff I've checked that the UDP packets are actually being sent, at least when I connect to a remote server.

My problem right now looks evident: the "select()" call for the UDP socket is not working. It times out and does not receive anything at all as it should (as I've checked that the info is being sent).


If I use only ony socket everything goes fine, but when I set up a second socket (in this case for the UDP packets) it won't receive anything.

I'm using two independent select() calls, one for each socket, and I don't know if that may be causing all the trouble. I'll post some code now.


This is the class delcaration:

#define PACKET_BUFFER_SIZE 512
#define PACKET_MAX_SIZE 512
#define IS_TIMEOUT 5

// Definition for our buffer datatype
struct buffer
{
char buffer[PACKET_BUFFER_SIZE]; // Packet buffer - 512 should be more than enough
unsigned int bytes; // Number of bytes currently in buffer
};

/**
* CInsim class to manage the Insim connection and processing of the packets
*/
class CInsim
{
private:
SOCKET sock; // TCP Socket (most packets)
SOCKET sockudp; // UDP Socket (if requested, for NLP and MCI)
byte using_udp; // 1 if we are using UDP for NLP or MCI packets
struct buffer gbuf; // Our global buffer
struct buffer lbuf; // Our local buffer
char packet[PACKET_MAX_SIZE]; // A buffer where the current packet is stored
fd_set readfd, exceptfd; // File descriptor watches
struct timeval select_timeout; // timeval struct for the select() call
struct buffer udp_gbuf; // (for NLP and MCI packets via UDP) Our global buffer
struct buffer udp_lbuf; // (for NLP and MCI packets via UDP) Our local buffer
char udp_packet[PACKET_MAX_SIZE]; // (for NLP and MCI packets via UDP) A buffer where the current packet is stored
fd_set udp_readfd, udp_exceptfd; // (for NLP and MCI packets via UDP) File descriptor watches
struct timeval udp_select_timeout; // (for NLP and MCI packets via UDP) timeval struct for the select() call
ofstream logfile;

public:
CInsim::CInsim(); // Constructor
// "int init(...)" Establishes connection with the socket and insim.
//+ The last argument ch_ver is a pointer to a IS_VER struct. If it's used an IS_VER packet
//+ will be returned. If ch_ver is not used in the call no IS_VER will be requested/returned.
int init (char *addr, word port, char *product, char *admin, struct IS_VER *pack_ver = NULL, byte prefix = 0, word flags = 0, word interval = 0, word udpport = 0);
int isclose(); // Closes connection from insim and from the socket
int next_packet(); // Gets next packet ready into "char packet[]"
char peek_packet(); // Returns the type of the current packet
void* get_packet(); // Returns a pointer to the current packet. Must be casted
int send_packet(void* packet); // Sends a packet to the host
int udp_next_packet(); // (UDP) Gets next packet ready into "char udp_packet[]"
char udp_peek_packet(); // (UDP) Returns the type of the current packet
void* udp_get_packet(); // (UDP) Returns a pointer to the current packet. Must be casted
int udp_send_packet(void* packet); // (UDP) Sends a packet to the host
};

This is the code used for establishing/connecting the two sockets and the connection to InSim:
(any var used not defined here is because it's a private member)

/**
* Initialize the socket and the Insim connection
* If "struct IS_VER *pack_ver" is set it will contain an IS_VER packet after returning. It's an optional argument
*/
int CInsim::init (char *addr, word port, char *product, char *admin, struct IS_VER *pack_ver, byte prefix, word flags, word interval, word udpport)
{
// Initialise WinSock
// Only required on Windows
WSADATA wsadata;

if (WSAStartup(0x202, &wsadata) == SOCKET_ERROR)
{
WSACleanup();
return -1;
}

// Create the TCP socket - this defines the type of socket
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

// Could we get the socket handle? If not the OS might be too busy or have run out of available socket descriptors
if (sock == INVALID_SOCKET)
{
closesocket(sock);
WSACleanup();
return -1;
}

// Resolve the IP address
struct sockaddr_in saddr;
memset(&saddr, 0, sizeof(saddr));

saddr.sin_family = AF_INET;

struct hostent *hp;
hp = gethostbyname(addr);

if (hp != NULL)
saddr.sin_addr.s_addr = *((unsigned long*)hp->h_addr);
else
saddr.sin_addr.s_addr = inet_addr(addr);

// Set the port number in the socket structure - we convert it from host byte order, to network
saddr.sin_port = htons(port);

// Now the socket address structure is full, lets try to connect
if (connect(sock, (struct sockaddr *) &saddr, sizeof(saddr)) < 0)
{
closesocket(sock);
WSACleanup();
return -1;
}

// If the user asked for NLP or MCI packets and defined an udpport
if ((udpport) && (flags >= ISF_NLP))
{
// Create the UDP socket - this defines the type of socket
sockudp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

// Could we get the socket handle? If not the OS might be too busy or have run out of available socket descriptors
if (sockudp == INVALID_SOCKET)
{
closesocket(sock);
closesocket(sockudp);
WSACleanup();
return -1;
}

// Resolve the IP address
struct sockaddr_in udp_saddr;
memset(&udp_saddr, 0, sizeof(udp_saddr));

udp_saddr.sin_family = AF_INET;

struct hostent *udp_hp;
udp_hp = gethostbyname(addr);

if (udp_hp != NULL)
udp_saddr.sin_addr.s_addr = *((unsigned long*)udp_hp->h_addr);
else
udp_saddr.sin_addr.s_addr = inet_addr(addr);

// Set the UDP port number in the UDP socket structure - we convert it from host byte order, to network
udp_saddr.sin_port = htons(port);

// Connect the UDP using the same address as in the TCP socket
if (connect(sockudp, (struct sockaddr *) &udp_saddr, sizeof(udp_saddr)) < 0)
{
closesocket(sock);
closesocket(sockudp);
WSACleanup();
return -1;
}

// We are using UDP!
using_udp = 1;
}

// Ok, so we're connected. First we need to let LFS know we're here by sending the IS_ISI packet
struct IS_ISI isi_p;
memset(&isi_p, 0, sizeof(struct IS_ISI));
isi_p.Size = sizeof(struct IS_ISI);
isi_p.Type = ISP_ISI;

if (pack_ver != NULL) // We request an ISP_VER if the caller asks for it
isi_p.ReqI = 1;

isi_p.Prefix = prefix;
isi_p.UDPPort = udpport;
isi_p.Flags = flags;
isi_p.Interval = interval;
memcpy(isi_p.IName, product, sizeof(isi_p.IName)-1);
memcpy(isi_p.Admin, admin, 16);

// Send the initialization packet
if(send_packet(&isi_p) < 0)
{
if (using_udp)
closesocket(sockudp);

closesocket(sock);
WSACleanup();
return -1;
}

// If an IS_VER packet was requested
if (pack_ver != NULL)
{
if (next_packet() < 0) // Get next packet, supposed to be an IS_VER
{
if (isclose() < 0)
{
if (using_udp)
closesocket(sockudp);

closesocket(sock);
WSACleanup();
return -1;
}
return -1;
}

switch (peek_packet()) // Check if the packet returned was an IS_VER
{
case ISP_VER: // It was, get it!
memcpy(pack_ver, (struct IS_VER*)get_packet(), sizeof(struct IS_VER));
break;
default: // It wasn't, something went wrong. Quit
if (isclose() < 0)
{
if (using_udp)
closesocket(sockudp);

closesocket(sock);
WSACleanup();
}
return -1;
}
}

return 0;
}

Here's the code for retrieving TCP packets. This seems to work fine in all cases:

/**
* Get next packet ready
* This function also keeps the connection alive as long as you keep calling it
*/
int CInsim::next_packet()
{
unsigned char oldp_size, p_size;
bool alive = true;

while (alive) // Keep the connection alive!
{
alive = false;
oldp_size = (unsigned char)*lbuf.buffer;

if ((lbuf.bytes > 0) && (lbuf.bytes >= oldp_size)) // There's an old packet in the local buffer, skip it
{
// Copy the leftovers from local buffer to global buffer
memcpy(gbuf.buffer, lbuf.buffer+oldp_size, lbuf.bytes-oldp_size);
gbuf.bytes = lbuf.bytes - oldp_size;

// Copy from global buffer back to the beginning of local buffer
memset(lbuf.buffer, 0, PACKET_BUFFER_SIZE);
memcpy(lbuf.buffer, gbuf.buffer, gbuf.bytes);
lbuf.bytes = gbuf.bytes;
}

p_size = (unsigned char)*lbuf.buffer;

while ((lbuf.bytes < p_size) || (lbuf.bytes < 1)) // Read until we have a full packet
{
// Set the timeout period
select_timeout.tv_sec = IS_TIMEOUT;
select_timeout.tv_usec = 0;

// Clear them
FD_ZERO(&readfd);
FD_ZERO(&exceptfd);

// Set them to watch our socket for data to read and exceptions that maybe thrown
FD_SET(sock, &readfd);
FD_SET(sock, &exceptfd);

int rc = select(sock + 1, &readfd, NULL, &exceptfd, &select_timeout);

if (rc == 0) // Timeout
continue;

if (rc < 0) // An error occured
return -1;

if (FD_ISSET(sock, &readfd)) // We got data!
{
// Recieve any waiting bytes
int retval = recv(sock, lbuf.buffer + lbuf.bytes, PACKET_BUFFER_SIZE - lbuf.bytes, 0);

// Deal with the results
if (retval == 0) // Connection has been closed at the other end
return -2;

if (retval < 0) // An error ocurred
return -1;

p_size = *lbuf.buffer;
lbuf.bytes += retval;
}
else if (FD_ISSET(sock, &exceptfd)) // An exception occured - we want to quit
return -1;
}

memset(packet, 0, PACKET_MAX_SIZE);
memcpy(packet, lbuf.buffer, p_size);

logfile << "UDP, ISP_" << (int)peek_packet() << ", " << (float)clock()/CLOCKS_PER_SEC << ", recv" << endl;

if ((peek_packet() == ISP_TINY) && (*(packet+3) == TINY_NONE))
{
alive = true;

struct IS_TINY keepalive;
keepalive.Size = sizeof(struct IS_TINY);
keepalive.Type = ISP_TINY;
keepalive.ReqI = 0;
keepalive.SubT = TINY_NONE;

// Send it back
if (send_packet(&keepalive) < 0)
return -1;
}
}

return 0;
}

And here's the code for retrieving UDP packets. This is the function that is giving me problems:

/**
* Get next UDP packet ready
*/
int CInsim::udp_next_packet()
{
unsigned char oldp_size, p_size;

oldp_size = (unsigned char)*udp_lbuf.buffer;

if ((udp_lbuf.bytes > 0) && (udp_lbuf.bytes >= oldp_size)) // There's an old packet in the local buffer, skip it
{
// Copy the leftovers from local buffer to global buffer
memcpy(udp_gbuf.buffer, udp_lbuf.buffer+oldp_size, udp_lbuf.bytes-oldp_size);
udp_gbuf.bytes = udp_lbuf.bytes - oldp_size;

// Copy from global buffer back to the beginning of local buffer
memset(udp_lbuf.buffer, 0, PACKET_BUFFER_SIZE);
memcpy(udp_lbuf.buffer, udp_gbuf.buffer, udp_gbuf.bytes);
udp_lbuf.bytes = udp_gbuf.bytes;
}

p_size = (unsigned char)*udp_lbuf.buffer;

while ((udp_lbuf.bytes == 0) || (udp_lbuf.bytes < p_size)) // Read until we have a full packet
{
// Set the timeout period
udp_select_timeout.tv_sec = IS_TIMEOUT;
udp_select_timeout.tv_usec = 0;

// Clear them
FD_ZERO(&udp_readfd);
FD_ZERO(&udp_exceptfd);

// Set them to watch our socket for data to read and exceptions that maybe thrown
FD_SET(sockudp, &udp_readfd);
FD_SET(sockudp, &udp_exceptfd);

int rc = select(sockudp + 1, &udp_readfd, NULL, &udp_exceptfd, &udp_select_timeout);

if (rc == 0) // Timeout
continue;

if (rc < 0) // An error occured
return -1;

if (FD_ISSET(sockudp, &udp_readfd)) // We got data!
{
// Recieve any waiting bytes
int retval = recv(sockudp, udp_lbuf.buffer + udp_lbuf.bytes, PACKET_BUFFER_SIZE - udp_lbuf.bytes, 0);

// Deal with the results
if (retval < 0) // An error ocurred
{
return -1;
}

p_size = *udp_lbuf.buffer;
udp_lbuf.bytes += retval;
}
else if (FD_ISSET(sockudp, &udp_exceptfd)) // An exception occured - we want to quit
return -1;
}

memset(udp_packet, 0, PACKET_MAX_SIZE);
memcpy(udp_packet, udp_lbuf.buffer, p_size);

logfile << "UDP, ISP_" << (int)udp_peek_packet() << ", " << (float)clock()/CLOCKS_PER_SEC << ", recv" << endl;

return 0;
}

I'm not sure if I'm doing something wrong with the sockets. If anyone is willing to check the code to help me I can provide tha full example and library code, executables, dlls and whatever you might want to give it a try.
MaKaKaZo
S2 licensed
Now that I'm not getting any help I'm wondering if anyone is currently using this TCP+UDP feature in InSim4 or everyone is just using full TCP for main and NLP/MCI packets in their applications.

Based on all the tests I've done I've come to the conclussion that the problem is in the InSim interface/reference or the server code, but not in my code. Let aside grabbing the UDP packets, it just seems like the server won't send the packets at all.

So, is someone currently using TCP+UDP???
FGED GREDG RDFGDR GSFDG