The online racing simulator
Very, very basic PHP
(52 posts, started )
Below works fine for me.


<?php 
while($run TRUE) {
    
$buffer $conn->read();
    switch(
substr($buffer03)) {
        case 
'MSO':
            echo 
trim($buffer)."\r\n";
            if(
preg_match('/^!quit/'$buffer)) die('Bye bye :(');
        break;
    }
    
usleep(10);
}
?>

Oh right, I didn't think of that! It makes perfect sense. Thankyou!

:bananalla

Another quick question - what's the ^L in the messages? It's a bit difficult to search for
Thanks
Thankyou so much for your help. I feel like I can do anything now (pfft )

I just tried forcing a certain view in the sim, and it's a great feeling when it works.

I found out that it's a good idea to put a big blank echo before each flush, of small amounts of data at least:

<?php 
echo(str_pad(''1024));
?>

I wondered why Firefox kept getting stuck while showing STA packets

It was because browsers have their own buffer and it was waiting for more data. But you knew that already. I just thought I'd put it down in case another clueless n00b like me wanders into the thread
So with a LAP packet... why is some of the data an array? Is the key to do with the connection?
player no.: Array ( [1] => 0 )
unique id: Array ( [1] => 2 )
lap time: 0:57.47

Didn't feel like making a new thread, and besides, this is still very, very basic PHP

Basically, I have this:

<?php 
while(TRUE) {    
    
$do $r;
    
/* if $startdelay sec has passed from join being disallowed, and is still disallowed, allow it */
    
echo "\r\njl : test";
    if(
$joinlock) {
        if(
time()-$joinlock['stamp'] >= $startdelay) {
            
$joinlock FALSE;
            
socket_write($sockpack('CCCCa64'681300str_pad('/msg Join Allowed'64"\0")));
        }
    }
    if(
socket_select($do$w$e$t)) {
 
// do stuffs
?>

My problem is that the section below is only tested when socket_select's status changes. I'd like these to be independent so that whatever else happens (like packets coming and going), if joining is still disallowed after $startdelay seconds of it last being set, it's allowed again. $joinlock['stamp'] is the time() at which joining was last disallowed.

How to?

Just in case that made no sense whatsoever, I've attached the whole scripture. Thanks if you can help, and even if you would if you could
Attached files
pax.txt - 4.5 KB - 222 views
You probably need ot put it inside the "while($data = socket_read($sock, 4)) {" loop so the condition will be checked each time you recieve a new packet.
That's exactly what I don't want I'd like the start delay timer to be independent of the socket_select part. The problem I have is this:
- I set $startdelay to 10 (sec)
- Join race, "Join Not Allowed" message comes up and works
- I start driving on my ax course without hitting cones
- A "Join Allowed" message should appear approximately 4-5 sec after the green light (6 sec countdown?)
- What actually happens is that I can drive all the way to the first split (22 sec) without the message triggering unless there's a socket event.

With my limited logical deducting skills, I'd guess the socket_select blocks until something happens, even though I set the socket to non-block.If possible I would prefer not having to move the first split into a suitalbe location to trigger a socket event at the right time.

It just occurred to me that it could work if I set a timeout to socket_select so that it runs every few hundred microsecs. Problem with that is that I'd like to have it without the timeout to conserver CPU cycles
int socket_select(array &$read, array &$write, array &$except, int $tv_sec [, int $tv_usec ]);

set $tv_sec to 1. this will set socket_select's timeout so it will return after one second, thus keeping out of a blocking mode.

Also, this returns an integer, thus the value of 0 is acceptable for correct oparation. You must be sure that your checking for the return value of FALSE, as it will give you that on an error, but that could be equated to 0.


<?php 
FALSE 
== 0// TRUE
FALSE === 0// FALSE
?>

Ideally you program everything around the select() call. So you only do stuff in reply to (insim) packets.
If however you want to do other things in the meantime, you have no choice but to introduce the timeout into the select() call. Just don't make it a very very small or instant timeout, but stick with a couple of milliseconds to begin with. You'll notice that CPU cycles are still very low and actually you won't notice any difference in CPU usage.

Until the day that PHP can do kernel polling (listening for network traffic without a select() call), you'll have to do it with timeouts.
PHP really is not brilliant for this kind of work, but ... it will work .
On another note, PHP 5.2.8 Released! In case anyone missed that up until now like me.
Yeah, I elected to take the timeout method. 200 millisec is working fine atm, if the script executes too slowly I'll reduce the timeout a bit. Thanks all
heya

im Just playing around with php & insim in the weekend and am in the same position as andy29 just trying to get php to talk to insim at the moment.

I have done a little PHP before and another guy in our LFS deals with PHP in his work so know abit more than me. Basicly pretty noob at this. This post has been pretty usefull have already read the PHP tutorial and afew other posts but hit a bit of a brick wall now. We jsut trying to do the very basics like andy just send a 'hello world' to LFS(z).

this is our code (PHP5) latest insim version.


<?php 
 
php
$errno 
0;
$errstr "";
$sender fsockopen("udp://127.0.0.1""63393", &$errno, &$errstr3);
// isi packet
$packet "ISI\0"// ISP_ISI, ReqI, Zero
$packet .= pack("C"63393); // word UDPPort
$packet .= pack("C"0); // word Flags
$packet .= pack("S"0); // byte Sp0
$packet .= pack("S""LFSS"); // byte Prefix
$packet .= pack("C"0); // word Interval
$packet .= str_pad("adminPW"16"\0"); // char Admin[16];
$packet .= str_pad("Test IT"16"\0"); // char IName[16];
echo strlen($packet);
fwrite($sender$packet);
fclose($sender);

?>

When we echo to strlen its 43 and the lfs server says 'recieved packet with invalid size' needs to be 44 according to insim.txt

during our playing around if we go $adminpw = "****" we get "password does not match your multiplayer admin password" and it is the right password we set on the sever.

can someone please give us a hand to just get started.
you've left out the Size byte which is the missing byte.

struct IS_ISI // InSim Init - packet to initialise the InSim system
{
byte Size; // 44

That's the old version of InSim, I think. Version 3 or something, back when the header was four chars. Need to look at docs\InSim.txt.
oh right. He's also using udp which I guess isn't recommended if you're new to this. Best use tcp.
ok oh its taken from that tutorial so yea, ok will change to TCP

so is $packet .= pack("C", 63393); the right sort of syntax?? that one is to set port, so we need a line to set Size right?

I'm slowly learning this stuff sorry for my dumbassness.

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
};
Quote from 4aged :ok oh its taken from that tutorial so yea, ok will change to TCP

so is $packet .= pack("C", 63393); the right sort of syntax?? that one is to set port, so we need a line to set Size right?

No not really. the C stands for one single byte, in which 63392 would never fit. So it's the wrong type to pack the value into. The correct value would be in this case S, which is a two byte value that can range from 0-65535. Or in other words, an unsigned short.
Unsigned means the value can only be bigger than 0 - there are no negative values. When you are dealing with a 'signed' type of variable then both positive and negative values are possible.
For an explanation on the pack() function and available types : http://nl3.php.net/manual/en/function.pack.php
You must really learn about these variable types and this function when you want to learn about InSim, because it's used for every InSim packet that you read and send.

Anyway, what I also wanted to say is, you do not need to set the UDP port when you're connecting with TCP. You _can_ set the UDP port, but you don't need it at this point. It would make things much too difficult for you.

Quote from 4aged :I'm slowly learning this stuff sorry for my dumbassness.

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
};

To get you started, compare the piece of php code you posted earlier with this IS_ISI packets description (struct).
You can see that you created this packet in several steps. One line per value of the struct to be exact.
So with that in mind, you can do the same for this correct IS_ISI packet :


<?php 
$AdminPass    
'adminPW';
$AppName    'Test IT';

$packet chr (44);                // Size of this packet
$packet .= chr (1);                // ISP_ISI (see the ENUMERATIONS FOR PACKET TYPES list in InSim.txt)
$packet .= chr (1);                // Reqi - something non-zero, so LFS will return an IS_VER packet
$packet .= chr (0);                // Must be zero

$packet .= pack ('S'0);        // byte UDP Port (not needed, so 0)
$packet .= pack ('S'40);        // 8 (keep text colours) + 32 (receive MCI packets)

$packet .= chr (0);                // Sp0
$packet .= '!';                    // Special host message prefix character - ! in this example.
$packet .= pack ('S'500);        // Time in ms between NLP or MCI packets (0 = none)

// char Admin[16]
$packet .= str_pad ($AdminPass16chr (0));
// char IName[16]
$packet .= str_pad ($AppName16chr (0));
?>

not tested, but I'm kinda sure it'll work.

BEWARE about this one :
$packet .= '!'; // Special host message prefix character - ! in this example.

If you do not need this, you cannot just delete the ! there. If you'd do that, then the size of the packet would not be 44 bytes anymore. In that case you should replace '!' with chr (0) for example (zero)

And one more thing I should mention is about the chr () function - I like to use that one to convert small numbers to binary format quickly. It's shorter than the pack function, but chr () can only do one thing : convert a number from 0-255 into binary form, usable in binary packets like InSim's.
Actually, chr () is meant for something else, to give you a character by it's numerical value (like chr (65) gives the character A), but it's the same conversion for single byte binary conversions.

I hope that is a bit educational
Hello, thanks for your reply! Just to inform you I am helping 4aged with this, well not really helping but doing this together!

I used your code, looks like this:


<?php 
$errno 
0;
$errstr "";
$sender fsockopen("127.0.0.1""63393", &$errno, &$errstr3);

$AdminPass    'adminPW';
$AppName    'Test IT';

$packet chr (44);                // Size of this packet
$packet .= chr (1);                // ISP_ISI (see the ENUMERATIONS FOR PACKET TYPES list in InSim.txt)
$packet .= chr (1);                // Reqi - something non-zero, so LFS will return an IS_VER packet
$packet .= chr (0);                // Must be zero

$packet .= pack ('S'0);        // byte UDP Port (not needed, so 0)
$packet .= pack ('S'40);        // 8 (keep text colours) + 32 (receive MCI packets)

$packet .= chr (0);                // Sp0
$packet .= '!';                    // Special host message prefix character - ! in this example.
$packet .= pack ('S'500);        // Time in ms between NLP or MCI packets (0 = none)

// char Admin[16]
$packet .= str_pad ($AdminPass16chr (0));
// char IName[16]
$packet .= str_pad ($AppName16chr (0));

fwrite($sender$packet);
fclose($sender);
?>

In LFS Dedi window - it comes up with: InSim Guest Closed. I run the above script in FireFox as I have a web server installed in our development environment.

Is this "InSim Guest Closed" error good or bad? If I wanted to send a message say "Hi, testing InSim from browser" how would I go about that?

You post was very informative and of course educational and we both appreciate your help.
You're getting that message because you're just sending the ISI packet and then closing the connection right away. You need to setup a continuous loop with a socket receive call to wait for incomming packets which are sent by LFS. Been years since I touched PHP, but here's some peudo(ish)-code for keeping the connection open.


socket.connect(host, port);

while (true)
{
buffer = socket.receive(BUFFER_SIZE);
if (buffer.length > 0)
{
processPacket(buffer);
}
}

thanks for your help, i think we will need php version of that though sorry.

our code so far


<?php 
php
// Variables
$errno        0;
$errstr       "";
$host         "127.0.0.1";
$insimPort    "63393";
$localPort    63390;
$AdminPass    "****";
$AppName      "LFSNZ Web App";

$sender fsockopen($host$insimPort, &$errno, &$errstr3);
// create receiver filestream
while ($localPort <= 65535)
{
  
$receiver = @stream_socket_server("tcp://$host:$localPort"$errno$errstrSTREAM_SERVER_BIND);

  if (
is_resource($receiver))
    break;

  
$localPort++;
  
$receiver false;
}

// Make the receiver stream nonblocking to be able to apply timeouts
stream_set_blocking($receiver0);


$packet chr(44);                            // Size of this packet
$packet .= chr(1);                            // ISP_ISI (see the ENUMERATIONS FOR PACKET TYPES list in InSim.txt)
$packet .= chr(1);                            // Reqi - something non-zero, so LFS will return an IS_VER packet
$packet .= chr(0);                            // Must be zero
$packet .= pack('S'0);                      // byte UDP Port (not needed, so 0)
$packet .= pack('S'40);                     // 8 (keep text colours) + 32 (receive MCI packets)
$packet .= chr(0);                            // Sp0
$packet .= '!';                               // Special host message prefix character - ! in this example.
$packet .= pack('S'500);                    // Time in ms between NLP or MCI packets (0 = none)
$packet .= str_pad($AdminPass16chr (0));  // char Admin[16]
$packet .= str_pad($AppName16chr (0));    // char IName[16]

if (fwrite($sender$packet))
    echo 
"Connected successfully.\n<br />";
else
    echo 
"Could not connect!\n<br />";


?>

Quote from LifeSteala :Is this "InSim Guest Closed" error good or bad? If I wanted to send a message say "Hi, testing InSim from browser" how would I go about that?

It should probably be pointed out that running an full InSim client (something that does more than a single thing before disconnecting - if that's all you're going to be doing then do disregard everything written in the following few sentences) within a web server isn't the most sensible idea for several reasons. The main is that all webservers provide a timeout - some hosts enforce it and some will allow you to change it, but it will eventually hit a limit, and when that happens your client will disconnect. Unless you're running the server yourself, it's almost certain that you'd be violating TOS with your host.

The accepted practise is to run PHP from the command line for anything of this nature.

Quote from 4aged :thanks for your help, i think we will need php version of that though sorry.

I'm not trying to be a dick or anything, but the PHP manual is rather easy to use and provides various examples for most functions and libraries.

Example #2 (if you use the sockets_* library) on this page should give you everything you need to get started, or this page from LXF (if you use the f* functions), in combination with Victor and DarkTimes' posts - you just need to subsitute out the HTTP protocol with the InSim protocol

If you get stuck or don't follow then holler and someone might pop something together for you.
Quote from the_angry_angel :If you get stuck or don't follow then holler and someone might pop something together for you.

Oh god yes, and hello boys, I'm BACK! Interesting to see victors take on the PHP to InSim subject, not sure if I like the chr function use tho.
With my distain for the car function that does not allow for reading and writing with one solid function, I would have to request what the correct data type is for each data type.

$ISI = pack('SSSSSSSCSa16a16', 44, 1, 1, 0, 0, 40, 0, '!', 500, substr($AdminPass, 0, 16, 16, "\0"), substr($AppName, 0, 16, 16, "\0"))

c = Signed Char;
[b]C = Unsigned Char;[/b] byte (prefix char) ... CRAP ... NOT CONSISTENT!

[b]a = NUL-Padded String;[/b] char
A = SPACE-Padded String;

[b]S = unsigned short (always 16 bit, machine byte order);[/b] word, byte

I fell this is correct, but I'd like to be sure.

Very, very basic PHP
(52 posts, started )
FGED GREDG RDFGDR GSFDG