The online racing simulator
a call for help from a stressed Team Member <G>
Hi All.
Well, as some of you know, i have been charged with creating the new STCC system. However, My programming skills (other than PHP) are rather sucky.

I have managed to get a basic idea of how Insim Works, and i would like some help from someone.

I am writing in Delphi, and becky gave me the source in Basic.

What i am basically trying to write is a Simple API that passes insim information to my PHP script, and then parses my PHP results back

for example if a user joins, It will send that information to my PHP script, my PHP script will look up that user, Do some maths etc with it and send the information back as a player message,

This is basically how the old system worked, except all the insim communication was done by becki's program, including driver aids / bans etc, It would be so much easier for me if i can use my native language (PHP) and there was a program in between basically feeding my PHP script events then returning it's reply to them.

can this be done? is anyone willing to help me?

Plllleaaassseeeee???

ty in advance

Mikey.
Hmm actually now i think about it. maybe i could just create the TCP Streams in PHP? <G>

err... i'll have a stab at that, unless someone can think of a better way to do it

ta

Mike
Doing the whole thing in PHP would certainly be easier, especially since you know it already.
yeah... i'd never played with TCP Streams in PHP... It's always been mysql etc, and basic FSock, Not keepalives etc.

Looks simple enough tho, so i gonna have a crack in PHP

ta

Mike
Hmm.. OK. I found some info on creating the listening server with PHP, and all seems well there.

I dont think i am constucting the insim packets correctly here (i'm a n00b outside of PHP).

Running from an insim turorial i have this :-

<?php 
$packet  
"";
$packet .= "ISI\0";
$packet .= pack("S"$localport);     
$packet .= pack("c"38);          
$packet .= pack("c"1);                  
$packet .= str_pad($adminPW16"\0");    
// Send packet
fwrite($sender$packetstrlen($packet)); 
?>

this connects, then based on a tutorial for INSIM i tried this.


<?php 
echo "Connected! Requesting Version packet...\n\n";
// The version-request packet is a simple InSimPack with ID "VER" and Value 0.
$packet "VER\0" pack("i"intval(0));
// send packet
fwrite($sender$packetstrlen($packet));
$packet false;
// receive answer from LfS: a packet with ID "VER"
$timeout time() + 2;
while (!
$packet && time() <= $timeout) {
  if (
$packet fread($receiver256)) {
    break;
  }
}
// check if really a version-packet arrived or something else we cant deal with at the moment
if (!$packet || substr($packet03) != "VER") {
  echo 
"No version package arrived, sorry :-(\n\n";
}
else {
  
// Parse version-package
  
$lfsV trim(substr($packet,  48)); // char
  
$lfsP trim(substr($packet126)); // char
  
$isv_raw substr($packet182);          // word
  
if(strlen($isv_raw) < 2) {
    
$isv_raw str_pad($isv_raw2"\0");
  }
  
$temp unpack("S",$isv_raw);
  
$insimV $temp[1];
  
  
// Show some version-information
  
echo "LfS Version-information:\n  LfS Product: $lfsP\n"
     
"  LfS Version: $lfsV\n  InSim Version: $insimV\n\n";
}
echo 
"Requesting InSimMulti-Package with Hostname now...\n\n";
// Now we request an InSimMulti-Package to get the LfS Hostname (if LfS is in multiplayer mode)
// To perform the request, we simply send an InSimPack with ID = "ISM" and Value = 0.
$packet "ISM\0" pack("i"intval(0));
// send packet
fwrite($sender$packetstrlen($packet));
$packet false;
// receive answer from LfS: a packet with ID "ISM"
$timeout time() + 2;
while (!
$packet && time() <= $timeout) {
  if (
$packet fread($receiver256)) {
    break;
  }
}

// check if really a ISM-packet arrived or something else we cant deal with at the moment
if (!$packet || substr($packet03) != "ISM") {
  echo 
"No InSimMulti-package arrived, sorry :-(\n\n";
}
// Get LfS connection type: are we connected to a client (0) or a server (1)?
$type_raw substr($packet41);
$temp unpack("c"$type_raw);
$type $temp[1];
echo 
"LfS type: " . (($type == 0)?"Client":"Server") . "\n\n";
// Get LfS Hostname
$hostname trim(substr($packet832));
if(empty(
$hostname)) {
  echo 
"Not in multiplayer mode\n\n";
}
else {
  echo 
"Hostname: $hostname";
}
// if we are connected to a server, restart it
if($type == 1) {
  echo 
"Now forcing server restart...\n\n";
  
// To inform the users, we will first send a MST(MessageTypePack)-packet to the server containing
  // the information that the server will be restarted now.
  // then we will force a server reinit, also using a MST.
  
$packet "MST\0" str_pad("^1SORRY, BUT THE SERVER WILL BE RESTARTED IN 3 SECONDS"64"\0");
  
fwrite($sender$packetstrlen($packet));
  
$packet "MST\0" str_pad("/reinit"64"\0");
  
fwrite($sender$packetstrlen($packet));
}
?>

then i disconnect


<?php 
$packet 
"ISC\0" pack("i"intval(0));
fwrite($sender$packetstrlen($packet));
fclose($sender);
fclose($receiver);
?>

This doesnt do anything exept connect and then disconnect?

If i can just figure out this basic bit.. I'm sure i can get it construct all the rest of what i need :-(

ty in advance to anyone that can help (btw i am writing for the new W17 patch),


Mikey
Hey. I've never done anything with InSim and PHP, but in that example it is sending old InSim V3 packets, which follow the "VER\0" format etc.. In the new InSim V4 it uses an entriely different packet structure, so you will need to rewrite the packets to use it with W17 etc..

I can try to give you some help with that if you like, but if you can understand how the packets in that example are put together, then it shouldn't be a huge stretch to rewrite them yourself from looking at the new InSim.txt file.

It might be an idea to work with the older non-test version of LFS until you've worked out how it works, then once you understand InSim you could rewrite it for V4.
Errr... No, lol.. I'm still trying to work out how the packet stuff is structured,

The old system (that becky wrote) had already translated the V3 info, and then simply asked my API based on simple strings (lfsuser=this&point=that) for example,

working with this is completely new to me.

If i had an example of a packet that you would send in the new format, with an explination of what does what in that packet, it would be greatly appreciated


ta

Mikey.
As I say I've never done any PHP/InSim before, but I had a look at the code and I think I figured it out. As you can see this is the original InSim initialisation packet from your existing code:

[COLOR=#000000][COLOR=#0000bb]
$packet [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#dd0000]""[/COLOR][COLOR=#007700];
[/COLOR][COLOR=#0000bb]$packet [/COLOR][COLOR=#007700].= [/COLOR][COLOR=#dd0000]"ISI\0"[/COLOR][COLOR=#007700];
[/COLOR][COLOR=#0000bb]$packet [/COLOR][COLOR=#007700].= [/COLOR][COLOR=#0000bb]pack[/COLOR][COLOR=#007700]([/COLOR][COLOR=#dd0000]"S"[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]$localport[/COLOR][COLOR=#007700]);
[/COLOR][COLOR=#0000bb]$packet [/COLOR][COLOR=#007700].= [/COLOR][COLOR=#0000bb]pack[/COLOR][COLOR=#007700]([/COLOR][COLOR=#dd0000]"c"[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]38[/COLOR][COLOR=#007700]);
[/COLOR][COLOR=#0000bb]$packet [/COLOR][COLOR=#007700].= [/COLOR][COLOR=#0000bb]pack[/COLOR][COLOR=#007700]([/COLOR][COLOR=#dd0000]"c"[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]1[/COLOR][COLOR=#007700]);
[/COLOR][COLOR=#0000bb]$packet [/COLOR][COLOR=#007700].= [/COLOR][COLOR=#0000bb]str_pad[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000bb]$adminPW[/COLOR][COLOR=#007700], [/COLOR][COLOR=#0000bb]16[/COLOR][COLOR=#007700], [/COLOR][COLOR=#dd0000]"\0"[/COLOR][COLOR=#007700]);
[/COLOR][/COLOR]

From looking at the old InSim.txt doc, which is used on the current 'stable' (0.5W) version of LFS, we can see the code above is the creation of this struct:


[FONT=Courier New, monospace][SIZE=2]struct InSimInit // UDP packet to initialise the InSim system[/SIZE][/FONT]
[FONT=Courier New, monospace][SIZE=2]{[/SIZE][/FONT]
[FONT=Courier New, monospace][SIZE=2] char Id [4]; // ISI + zero[/SIZE][/FONT]
[FONT=Courier New, monospace][SIZE=2] word Port; // Port for UDP replies from LFS (0...65535)[/SIZE][/FONT]
[FONT=Courier New, monospace][SIZE=2] byte Flags; // Bit flags for options - see below[/SIZE][/FONT]
[FONT=Courier New, monospace][SIZE=2] byte NodeSecs; // Number of seconds between NLP or MCI packets (0=none)[/SIZE][/FONT]
[FONT=Courier New, monospace][SIZE=2] char Admin [16]; // Admin password (required if set in LFS host options)[/SIZE][/FONT]
[FONT=Courier New, monospace][SIZE=2]};[/SIZE][/FONT]

So we need to rewrite this for the new version of LFS, so looking in the InSim.txt file for W17, we can see that old InSimInit struct has been changed to the snazzy new IS_ISI struct:

struct IS_ISI // InSim Init - packet to initialise the InSim system
{
byte Size; // 44
byte Type; // ISP_ISI
byte ReqI; // If non-zero LFS will send an IS_VER packet
byte Zero; // 0

word UDPPort; // Port for UDP replies from LFS (0 to 65535)
word Flags; // Bit flags for options (see below)

byte Sp0; // 0
byte Prefix; // Special host message prefix character
word Interval; // Time in ms between NLP or MCI (0 = none)

char Admin[16]; // Admin password (if set in LFS)
char IName[16]; // A short name for your program
};

So to rewrite this packet to meet the current specification I believe you would need to do this:


$packet = "";
$packet .= pack("c", 44); // Size of the packet
$packet .= pack("c", 1); // Packet ID, which is from the packet types enum
$packet .= pack("c", 1); // Set to 1 for LFS to send a version packet in response
$packet .= pack("c", 0); // Zero
$packet .= pack("S", 0); // The port for InSim to send back Udp packets, use zero for the same port as we are sending on
$packet .= pack("S", 1); // The bit flags, which allows you to set some options, check insim.txt for info
$packet .= pack("c", 0); // Sp0, which I think is spare or something...
$packet .= pack("c", "$"); // Message prefix character
$packet .= pack("S", 0); // Milliseconds to wait between sending NLP or MCI packets, if those are enabled in the bit flags
$packet .= str_pad("MyAdminPass", 16, "\0"); // The LFS admin password
$packet .= str_pad("Test Program", 16, "\0"); // A short name for your program

So that would create an equivalent packet for InSim V4. I hope that makes sense to you... I have not tested the above example, but I hope it points you on the right track. There are some very experienced PHP/InSim programmers on this forum, so I will leave it up to them to provide more detailed information. I'm a sad C# geek.

Edit: As I said before, I think it's going to be harder to learn InSim from the new version, as in my view it's actually more complicated, plus it will change again in the final patch X as Scawen is still tweaking it to perfection. I'd suggest messing about with the version of InSim V3 in 0.5W, which you original example should work on, and then move over to V4 for patch X when you are confident you understand how it all works together. I've been learning InSim over the last few weeks and I started with the old version for this very reason, now I 'get it' I'm about 75% through a whole C# InSim library I've been writing.
If it helps, the basic surmise behind InSim v4 TCP is:
* Setup a global buffer and way to record the number of bytes in the buffer
* Connect
* Send ISP_ISI, Send ISP_VER (to check the version is compatible)
* Loop
** If data is available, receive into local buffer
** Check global buffer and prepend any bytes to the contents of the local buffer. Clear global buffer
** Loop
*** Assume the first byte is the packet size. Read upto that number of bytes, and do what you want with it
*** Check to see if the number of bytes remaining is >= to the number contained in the next packet. If it is parse it
*** Repeat until number of bytes remaining < expected packet size
** Copy any remaining bytes into the global buffer
** Answer any keepalives, etc. anything you've put into your output queue
** Repeat until you want to quit
* Disconnect

If you're doing this in a non-memory managed language (such as C, you'll take a slightly different route - see the luaLFS source), but it's basically the same idea. The problem with this is that if things get out of sync, it'll totally screw up the stream.
Yeah. The only Issue is, I been given a dealine of, by the Next release to get this working. Becky's stuff works until we move to Patch W, then The STCC (as it was formerly known) is dead, unless i get this sorted, lol

We got our Resident Expert on the case now too looking over all these posts to help me come to grips with it.


Thanks loads for all your help guys
You can though connect to InSim v4 using UDP exactly like before, so long as you change the packets to the new structure. I actually do find UDP easier, so I'd suggest only using TCP if you require guaranteed delivery of packets.
This might be of use, though my personal opinion is that PHP is ill equipped to be implement a daemon efficiently.

http://devzone.zend.com/node/view/id/1086

Bear in mind that if you want to keep listening to requests while you process ones that have just come in, you will need to invoke the request handler through CURL or some similar method.

Also, you should keep the daemon script as light as possible. PHP is a memory whore at the best of times with static scripts, never mind a daemon script.
Quote from mkserve :Yeah. The only Issue is, I been given a dealine of, by the Next release to get this working. Becky's stuff works until we move to Patch W, then The STCC (as it was formerly known) is dead, unless i get this sorted, lol

We got our Resident Expert on the case now too looking over all these posts to help me come to grips with it.


Thanks loads for all your help guys

I saw you used my tutorial from the wiki. This one is completely useless because it is not already adapted to the new InSim. I'll have a free day tomorrow, I'm gonna check out how the new insim works and rewrite the tutorial then.
Quote from St4Lk3R :I saw you used my tutorial from the wiki. This one is completely useless because it is not already adapted to the new InSim. I'll have a free day tomorrow, I'm gonna check out how the new insim works and rewrite the tutorial then.

Well, i wouldn't say useless, it gave me a good starting block to look at, I was hoping i could just modify the packets to fit in with Insim v4. My Problem is, this is the first time i've worked in PHP outside of delivering and retrieving simple strings.

I'm going to continue with this method for personal usage only, as the new manager is being written in basic, as it was before.. However i think if i can crack making this work in PHP, it would ease some future projects we have up our sleeve, and hopefully give me a much better understanding of Insim

Again, i would like to thank everyone for thier help so far.. One of the things i have come to love about LFS, is the community involved with it
Give me like 5 days. Seeing as lurLFSd is pretty much MIA, I'm going to make my own InSim Program in PHP. Programmable via php plugins and all.
Quote from Dygear :Give me like 5 days. Seeing as lurLFSd is pretty much MIA, I'm going to make my own InSim Program in PHP. Programmable via php plugins and all.

sounds like a kewl project.
Quote from mkserve :sounds like a kewl project.

Good news, (for the safety of the project) filur will be working on lurLFSd again after the patch X comes out.
Where is Bespoke?!!
Where is Bespoke?!!

FGED GREDG RDFGDR GSFDG