The online racing simulator
Searching in All forums
(947 results)
Racon
S3 licensed
Last edited by Racon, .
Racon
S3 licensed
In single player mode, in the mods screen. There's a button under the mods.
Racon
S3 licensed
Sorry, I should have made clear: I don't use those automatic startup scripts - I'm not calling them, only LFS is (the automated calling). IE, whatever LFS does is triggering the warning.

I've just checked, and the script is still being run despite the warning.

Racon
S3 licensed
I'm getting a notice about not being able to run the automated scripts that I don't think was there before:

Quote :Script 'sequential' cannot be run from a script

I also got one for 'road', but not for 'ev'.
Racon
S3 licensed
Last edited by Racon, .
Racon
S3 licensed
Last edited by Racon, .
Racon
S3 licensed
No problem, and good luck Thumbs up

There's some discussion/help about direct access on LFS discord programming channel sometimes... it's worth joining if you're going to go on memory adventures Smile
Racon
S3 licensed
Some programs use InSim to manage the interface, but also do direct reading/writing of the memory of the running LFS exe as well. That kind of thing is beyond me I'm afraid Smile
Racon
S3 licensed
You can't use InSim to set a rev limit, if that's what you mean - the OutGauge part is read-only. You could warn people about high revs, but you can't force them to be cut.

Yes, if other players want to use your app, they will need to enable OutGauge also before the app will receive OutGauge packets.
Racon
S3 licensed
You can only get that information from the OutGauge packet, so it's only available to local InSims. You need OutGauge configured in LFS's cfg.txt to get LFS to start sending it InSim, too.
Racon
S3 licensed
Good job in the e-challenge... those blue-flaggers always gain that last chunk of time and burst into the mirrors out of nowhere, don't they? Big grin

These changes to the text commands reminded me of something I thought about a while back - using /o and /i messages bound to a wheel button in order to communicate with an InSim. I would watch the packets for a command, then call my 'insim button has been clicked' function to simulate receiving a click.

Would it be possible to have a /click command that directly triggered an InSim click inside LFS? I imagine it would need to be /click [local|host] ClickId, or /clicklocal ClickId and /clickhost ClickId.

If it could be done that way we could use it with any existing InSim, not just ones that were written to catch hidden i/o messages. We could build InSim menus that could be navigated without taking your hands off the wheel.

edit: just thought, you'd have to check the button id was displayed to that user, else people could cause all sorts of mischief by spamming random click ids on servers where the security is done by showing a panel or not. I'm sure you would, but better to say than not Wink
Last edited by Racon, .
Object Groups
Racon
S3 licensed
A layout-building helper to hold multiple, nameable groups of objects which can be saved to file.

- Click the group's name to change it
- Click 'set' to assign the selected objects to that group
- Click 'set' with no selected objects to clear the group
- Click 'get' to load a saved group into the hand/cursor
- Click 'place' to place the objects in their original position
- Click the filename to change it
- Click 'save' to save the current groups and names to file
- Click 'load' to load from file

Here's a quick demo video by way of a guide:



Requirements:
PIE executable (https://www.lfs.net/forum/thread/98929)
InSim enabled in LFS (port 29999 default)

Usage:
Fuel Monitor
Racon
S3 licensed
A small display to help manange fuel/energy use in a race.

FuelMonitor shows the following four pieces of information, from left to right:

Updated live:
1) fuel / energy remaining

Updated at lap end:
2) fuel budget (fuel left per lap until race end)
3) fuel usage (fuel usage on previous lap)
4) range (predicted lap count when fuel runs out, if previous lap usage is maintained)



Requirements:
PIE executable (https://www.lfs.net/forum/thread/98929)
InSim enabled in LFS (port 29999 default)
OutGauge enabled in LFS (port 49999 default)

Usage:
Last edited by Racon, .
Tutorial 7: Object info
Racon
S3 licensed
// [Object Info] //////////////////////////////////////////////////////////////

Now we'll look at layout objects, button clicks and handling multiple
buttons.

We'll make a small panel that will give us information about a selected
object when we click on the header. We'll make a function called 'drawpanel'
that can be called at any time to initialise or update the entire panel.

We'll set some variables to control our panel, and then draw our panel.
We'll also make a variable to store our target object, so that our panel
doesn't need the object to be passed to it.

We'll need to hook the BTC object to detect button clicks. Here we only have
one to check, and if we find it we'll send a TTC packet that requests the
current layout editor selection.

We'll hook the AXM packet to watch for replies, and discard any that are not
of the correct type. We'll find the first object and store it before calling
for the panel to be redrawn.

Finally, we'll define our function to draw the panel. We'll make the first
button clickable, and then, if there is an object saved, we'll loop through
the fields and output them as a row. Note that we're increasing the id value
as we go - we'll use this next to delete any leftover buttons from a previous
draw using a BFN packet.


objectinfo.php:


<?php 

function PIE_settings()
  {
    return array(
'flags'      => ISF_LOCAL,
                 
'insimname'  => 'ObjectInfo');
  }
  
function 
PIE_start()
  {
    
$PIE PIE::connect();
    
    
$PIE->set('panelbaseid',      20);
    
$PIE->set('paneltop',         7);
    
$PIE->set('panelleft',        154);
    
$PIE->set('panelwidth',       20);
    
$PIE->set('panelbheight',     5);
    
$PIE->set('object',           array());
    
    
drawpanel();
  }
  
function 
PIE_BTC($data)
  {
    
$PIE PIE::connect();
    
    
$bid $PIE->get('panelbaseid');
    if (
$data['ClickID'] == $bid)
      
PIE_sendTTC(TTC_SEL);
  }
  
function 
PIE_AXM($data)
  {
    if (
$data['PMOAction'] != PMO_TTC_SEL)
      return;
    
    if (
$data['NumO'] < 1)
      
$object = array();
    else
      
$object $data['Info'][0];
    
    
$PIE PIE::connect();
       
    
$PIE->set('object'$object);
    
drawpanel();
  }
  
function 
drawpanel()
  {
    
$PIE PIE::connect();
    
    
$bid      $PIE->get('panelbaseid');
    
$top      $PIE->get('paneltop');
    
$left     $PIE->get('panelleft');
    
$width    $PIE->get('panelwidth');
    
$bheight  $PIE->get('panelbheight');
    
    
$object   $PIE->get('object');
    
$id       $bid;
    
    
$packet = array('Type'     => ISP_BTN,
                    
'ClickID'  => $id++,
                    
'BStyle'   => ISB_DARK ISB_CLICK,
                    
'T'        => $top,
                    
'L'        => $left,
                    
'W'        => $width,
                    
'H'        => $bheight,
                    
'Text'     => '^7Get Object Info');
    
PIE_sendpacket($packet);
        
    
$row 1;
    foreach(
$object as $k=>$v)
      {
        
$packet = array('Type'     => ISP_BTN,
                        
'ClickID'  => $id++,
                        
'BStyle'   => ISB_DARK ISB_RIGHT,
                        
'T'        => $top + ($row $bheight),
                        
'L'        => $left,
                        
'W'        => 8,
                        
'H'        => $bheight,
                        
'Text'     => $k.':');
        
PIE_sendpacket($packet);
        
        
$packet = array('Type'     => ISP_BTN,
                        
'ClickID'  => $id++,
                        
'BStyle'   => ISB_DARK ISB_LEFT,
                        
'T'        => $top + ($row $bheight),
                        
'L'        => $left+8,
                        
'W'        => 12,
                        
'H'        => $bheight,
                        
'Text'     => $v);
        
PIE_sendpacket($packet);
        
$row += 1;
      }
    
    
$max $bid 12;
    if (
$id $max)
      
PIE_sendpacket(array( 'Type'      => ISP_BFN,
                            
'SubType'   => BFN_DEL_BTN,
                            
'ClickID'   => $id,
                            
'ClickMax'  => $max));
    
  }
 
?>

command line:

> pie tutorials\objectinfo.php

Tutorial 6: Headsup
Racon
S3 licensed
// [Headsup] //////////////////////////////////////////////////////////////////

Now, let's make ourselves a local headsup speedometer. We'll need to set up
OutGauge in LFS for this, by editing the cfg.txt file (with LFS closed). We'll
need to set 'OutGauge IP' to localhost, choose a free port for 'OutGauge
Port', set 'OutGauge Mode' to 2 (local and viewed players) and 'OutGauge
Delay' to 10 (1/100th second).

In our 'PIE_settings' function, we need to add 'outgaugehost' and
'outgaugeport' settings to match.

We will also define a 'PIE_OutGauge' function, to catch the packets once
they begin arriving. Inside this function, we will format the car's speed and
send it to screen as an InSim button. As this packet uses the UDP protocol, we
will first check the timestamp and discard any packets that have been received
out of order.

The speed supplied in the OutGauge packet is in metres per second, so we
need to multiply by 2.2 to get our speed in miles per hour, or 3.5398 to get
kilomtres per hour.


LFS's cfg.txt file, OutGauge lines only:

OutGauge Mode 2
OutGauge Delay 10
OutGauge IP 127.0.0.1
OutGauge Port 49999

headsup.php:


<?php 

function PIE_settings()
  {
    return array(
'flags'              => ISF_LOCAL,
                 
'outgaugehost'       => '127.0.0.1',
                 
'outgaugeport'       => 49999);
  }
  
function 
PIE_OutGauge($data)
  {
    
$PIE PIE::connect();
    
    
$lasttime $PIE->get('lastOutGauge');
    
$thistime $data['Time'];
    
    
$PIE->set('lastOutGauge'$thistime);
    if (
$lasttime $thistime)
      return;
    
    
$speed number_format(($data['Speed']*3.5398), 1);
    
PIE_sendpacket(array( 'Type'     => ISP_BTN,
                          
'ClickID'  => 7,
                          
'BStyle'   => 0,
                          
'T'        => 147,
                          
'L'        => 90,
                          
'W'        => 20,
                          
'H'        => 8,
                          
'Text'     => $speed));
  }

?>

command line:

> pie tutorials\headsup.php




// [Headsup log] //////////////////////////////////////////////////////////////

Finally, let's use some more native PHP. We'll take the previous headsup
program and add some logging to a file - we'll record our speed in a CSV file,
ready for importing into another program.

We'll need to open the file for appending at the start and close it at the
end in order to save overhead - we don't need to do this every time we write
as we can store the file pointer in a PIE variable. Note, we'll need to use
the constant 'PIE_SCRIPTDIR' to reference the folder that the PIE script is
running from, if we want to use relative file paths.

In our PIE_OutGauge function, we simply check the pointer is valid and write
a line to the file. We'll write the time and the speed separated by a comma,
and a PHP constant for the carriage at the end of the line.


headsuplog.php:


<?php 

function PIE_settings()
  {
    return array(
'flags'              => ISF_LOCAL,
                 
'outgaugehost'       => '127.0.0.1',
                 
'outgaugeport'       => 49999);
  }
      
function 
PIE_start()
  {
    
$PIE PIE::connect();
    
    
$fp fopen(PIE_SCRIPTDIR.'speedlog.csv''w');
    
$PIE->set('filepointer'$fp); 
  }
      
function 
PIE_OutGauge($data)
  {
    
$PIE PIE::connect();
    
    
$lasttime $PIE->get('lastOutGauge');
    
$thistime $data['Time'];
    
    
$PIE->set('lastOutGauge'$thistime);
    if (
$lasttime >= $thistime)
      return;
    
    
$speed number_format(($data['Speed']*3.5398), 1);
    
PIE_sendpacket(array( 'Type'     => ISP_BTN,
                          
'ClickID'  => 7,
                          
'BStyle'   => 0,
                          
'T'        => 147,
                          
'L'        => 90,
                          
'W'        => 20,
                          
'H'        => 8,
                          
'Text'     => $speed));
                          
    
$fp $PIE->get('filepointer');
    if (
$fp)
      
fwrite($fp''.$thistime.','.$speed.PHP_EOL);    
  }
  
function 
PIE_shutdown()
  {
    
$PIE PIE::connect(); 
    
    
$fp $PIE->get('filepointer');
    
fclose($fp);
  }

?>

command line:

> pie tutorials\headsuplog.php

Tutorial 5: No-repair reset
Racon
S3 licensed
// [No-repair reset] //////////////////////////////////////////////////////////

Now, we'll make a host program that will allow users to put their cars back
upright after a crash, without repairing damage. We'll need access to the MCI
data, so we'll need the 'ISF_MCI' bit set on our flags.

We'll use another method of setting up this time around, and put what we
need inside the main settings for our program. This allows us to easily
override these settings on a per-server basis with config files.

We'll introduce another function here, 'PIE_commands' is called when a
connection types any command into chat. It is passed the command, arguments
and the UCID of the connection who called it. We'll use this to allow players
to request a reset.

In the case of resetting a car we'll need the PLID of the car to reset, but,
we have the UCID of the sender, and there can be more than one player per
connection. The function 'PIE_PLIDfromUCID' can be used to return a single
PLID value from a UCID (prioritising human players over AI), or
'PIE_PLIDsfromUCID' (plural) will return an array of all of them.

We'll add a mechanism for a delay, and make it customisable. This allows
server administrators to punish usage with a time penalty. The randomness can
be used to help thwart would-be reset-abusers.

We'll use our delay to set a callback for the flip, and then inform our user
immediately so that they don't spam the command. As we still have our UCID
from earlier, we'll use 'PIE_sayto' instead of 'PIE_say' this time so that we
don't spam the rest of the users.

Inside our flip function, we're going to use some stored helper data to find
out where our car is. Even if we don't hook the MCI packet by defining a
'PIE_MCI' function, PIE keeps a copy of the latest CompCar for each player,
indexed by PLID.

We'll add a speed check to prevent a reset being used while the car is in
motion. We're converting our raw data value to more standard units for the
sake of those who are configuring our program after us - all units are
provided in InSim.txt.

Finally, we'll send the JRR packet to reset the car with the no-repair
option. The JRR packet expects coordinates in the same scale as an autocross
object (as in an AXM packet) and ours, from the MCI packet, are in a different
scale. We'll convert our values and we'll add 1 to our Z value to lift the car
by 25cm (to ensure a safe reset in the case of a highly-damaged car). For the
heading, we'll rotate the car by 180 degrees as we scale, and make our value
safe by modding with the maximum value.


flip.php:


<?php 

function PIE_settings()
  {
    return array(
'flags'      => ISF_MCI,
                 
'maxspeed'   => 0.2,       // metres/second
                 
'mindelay'   => 1,         // seconds, float
                 
'maxdelay'   => 3,
                 
'insimname'  => 'Flip');
  }

function 
PIE_commands($command$args$ucid)
  {
    switch(
$command)
      {
        case 
'reset':
        case 
'rescue':
        case 
'pieflip':
          
$PIE        PIE::connect();
          
          
$plid       PIE_PLIDfromUCID($ucid);
          
$mindelay   $PIE->get('PIE_settings',  'mindelay');
          
$maxdelay   $PIE->get('PIE_settings',  'maxdelay');
          
          
$delayrange $maxdelay $mindelay;
          
$delay      $mindelay + ((mt_rand(0,100)/100) * $delayrange);
          
$time       microtime(true) + $delay;
          
PIE_setcallback($time'flip'$plid);
          
          
PIE_sayto($ucid'flip (delayed by '.$delay.')');
      }
  }
  
function 
flip($plid)
  {
    if (empty(
$plid))
      return 
false;
    
    
$PIE PIE::connect();
    
$MCI $PIE->get('PIE_MCI',       $plid);
    
$max $PIE->get('PIE_settings',  'maxspeed');
        
    if (empty(
$MCI))
      return 
false;
    
    
$speed = ($MCI['Speed'] / 327.68);  
    if (
$speed $max)
      return 
false;   
    
    
$x round($MCI['X'] / 4096);
    
$y round($MCI['Y'] / 4096);
    
$z max(0round($MCI['Z'] / 16384))+1;
    
$heading = (round($MCI['Heading'] / 256) + 128) % 256;
        
    
$packet = array('Type'      => ISP_JRR,
                    
'PLID'      => $plid,
                    
'JRRAction' => JRR_RESET_NO_REPAIR,
                    
'X'         => $x,
                    
'Y'         => $y,
                    
'Zbyte'     => $z,
                    
'Flags'     => 0x80,
                    
'Heading'   => $heading);
    
PIE_sendpacket($packet); 
  }  

?>

host.cfg: (set your own host/port/adminpass)

flags=0
host=1.2.3.4
port=54321
adminpass=secretpassword

command line:

> pie tutorials\flip.php host.cfg

Tutorial 4: Random lights
Racon
S3 licensed
// [Random lights] ////////////////////////////////////////////////////////////

Now let's look at another way to repeat actions, how to store and retrieve
values, and, as we're getting more complicated now, let's look at some simple
live debugging too.

We're going to make a program that will assign random lights to startlight
objects at a set rate, and then we'll fiddle with it while it runs.

In the previous examples we have not needed to communicate between
functions, but this time we're going to count how many times the lights have
changed. We will need to keep track of the count between multiple calls of the
light-changing function. To do this we'll use the PIE object - an object that
contains InSim information, helper functions, and is always there in the
background.

Important note: To use the PIE object, we must first connect to it. We do
this by assigning it to the $PIE variable. This variable can then be used
throughout the function. You must do this inside each function that needs to
use the PIE object. It's fatal PHP error to forget this step, and PIE can't
protect you from forgetting to do this part, sorry!

In our 'PIE_start' function, once we have a $PIE variable, we can use the
'set' function to store data for later use. We'll store some id numbers to
specify which lights to change, a delay to regulate the speed, and a counter
just for example.

We've got a new function 'PIE_clock', which is called every second with the
unix timestamp as a parameter. We'll connect to the PIE object, retrieve the
delay and then use that to call the 'randomiselights' function every so many
seconds.

In our 'randomiselights' function, we again connect to the PIE object first,
as we'll need our stored data. We'll retrieve our array of light ids and loop
through them - for each light we'll set a random set of bulbs. We'll use the
OCO packet to control our lights, specifying objects by the identifier set in
LFS.

Finally, we'll add one to our counter.

Note, you will need the some startlight objects with the correct identifier
id on your layout, and the layout must be optimised before InSim can control
them. The easiest way to do this is to restart the currect session.

Once we see the lights changing, we can do some live debugging:

We can inspect our counter with a text command ";piepeeku lightchanges". We
can also use this to see our current delay with ";piepeeku lightdelay", and we
can alter it (let's say we'll set it to 7 instead of 4), with ";piepokeu
lightdelay 7".

Note that these commands are limited to admins. In host mode, PIE uses the
server admin status to determine who's allowed to run these commands. In local
mode, you will need to specify your account name in the settings.


randomlights.php:


<?php 

function PIE_settings()
  {
    return array(
'flags'      => 0,
                 
'insimname'  => 'RandomLights');
  }
  
function 
PIE_start()
  {
    
$PIE PIE::connect();
    
    
$PIE->set('lightids',     array(2,3,4));
    
$PIE->set('lightdelay',   4);
    
$PIE->set('lightchanges'0);
  }
  
function 
PIE_clock($t)
  {
    
$PIE PIE::connect();
    
    
$delay $PIE->get('lightdelay');
    
$delay max(1$delay);
    if (!(
$t%$delay))
      
randomiselights();
  }
  
function 
randomiselights()
  {
    
$PIE PIE::connect();
    
    
$lights $PIE->get('lightids');
    foreach(
$lights as $light)
      {
        
$bulbs mt_rand(0,15);
        
PIE_sendpacket(array( 'Type'        => ISP_OCO,
                              
'OCOAction'   => OCO_LIGHTS_SET,
                              
'Index'       => AXO_START_LIGHTS,
                              
'Identifier'  => $light,
                              
'Data'        => $bulbs));
      }    
      
    
$count $PIE->get('lightchanges')+1;
    
$PIE->set('lightchanges'$count);
  }
 
?>

command line:

> pie tutorials\randomlights.php host.cfg





// [Debugging in code] ////////////////////////////////////////////////////////

Now, we'll do some more debugging - you can never have enough ways to find
out what's going on! We'll take our previous lights program and modify the
randomiselights function.

We'll build two strings to tell us what's going on as each light is set, one
for console debugging now and another saved in an array for outputting to chat
later.

We use the 'PIE_debugout' function to optionally output debugging messages
to the PIE console. The first parameter is the level of debugging that should
be required for this message to be output, the second is the message itself.

Alternatively, we can use the 'PIE_debugcheck' function to see if a certain
level of debugging is enabled, in order to deal with the debugging ourselves.
Here we'll send it to chat. We'll use a different debugging level so that we
can toggle these two debugging options independently.

We also have a new helper function 'textbulbs', to more easily see which
bulbs should be set for comparison. (Note, this is correct only for startlight
objects, main lights follow a different pattern.)


randomlightsdebug.php:


<?php 

function PIE_settings()
  {
    return array(
'flags'      => 0,
                 
'insimname'  => 'RandomLights');
  }
  
function 
PIE_start()
  {
    
$PIE PIE::connect();
    
    
$PIE->set('lightids',     array(2,3,4));
    
$PIE->set('lightdelay',   4);
    
$PIE->set('lightchanges'0);
  }
  
function 
PIE_clock($t)
  {
    
$PIE PIE::connect();
    
    
$delay $PIE->get('lightdelay');
    
$delay max(1$delay);
    if (!(
$t%$delay))
      
randomiselights();
  }
  
function 
randomiselights()
  {
    
$PIE PIE::connect();
    
    
$lights $PIE->get('lightids');
    
$debug = array();    
    foreach(
$lights as $light)
      {
        
$bulbs mt_rand(0,15);
        
PIE_sendpacket(array( 'Type'        => ISP_OCO,
                              
'OCOAction'   => OCO_LIGHTS_SET,
                              
'Index'       => AXO_START_LIGHTS,
                              
'Identifier'  => $light,
                              
'Data'        => $bulbs));
                              
        
$debug[] = '#'.$light.': '.textbulbs($bulbs);
        
$msg $t.' lights #'.$light.' set to '.$bulbs.' ('.textbulbs($bulbs).')';
        
PIE_debugout(PIE_DEBUGUSER1$msg);
      }    
      
    
$count $PIE->get('lightchanges')+1;
    
$PIE->set('lightchanges'$count);
      
    if (
PIE_debugcheck(PIE_DEBUGUSER2))
      {
        
$msg 'change '.$count.': '.implode(', '$debug);
        
PIE_say($msg);
      }
  }
  
function 
textbulbs($bulbs)
  {
    
$return '';
    
$return .= ($bulbs 1) ? 'R' '-';
    
$return .= ($bulbs 2) ? 'Y' '-';
    
$return .= ($bulbs 8) ? 'G' '-';
    
    return 
$return;
  }

?>

command line:

> pie tutorials\randomlightsdebug.php host.cfg

Tutorial 3: Race start message
Racon
S3 licensed
// [Race start message] ///////////////////////////////////////////////////////

Now let's try sending packets. We'll use buttons instead of chat to send
messages at the start of each race, using the BTN packet.

To send a packet with PIE, we need only make an associative array with the
required fields defined and pass it to the 'PIE_sendpacket' function. PIE sets
default values for all the fields, so you can leave out anything you don't
need. PIE also handles the 'ReqI' and 'Size' fields, so you can forget those
too.

We'll hook the RST packet and send our button packets from there. As we're
making a host InSim, we'll need to specify a UCID to send the buttons to.
We'll use the use the special value 255 to send them to all connections.

Buttons will persist until cleared by another packet, or the user, or the
InSim is closed. So, we'll have to clean it up ourselves after a delay. We
can't wait with a sleep function because PIE needs to keep doing other things
in the meantime, so we will use a callback.

In this case we'll make a 'killbutton' function to send another packet, BFN.
We'll use the 'PIE_setcallback' function to tell PIE when to call our
function, and what value to pass to it as a parameter. (We'd need to use an
array for passing multiple values, but in this case we only need the button's
ClickID). We'll set a time 6 seconds in the future in this case, and pass the
relevent ClickID in the args parameter.

racestartmessage.php:


<?php 

function PIE_RST($data)
  { 
    
$packet = array('Type'     => ISP_BTN,
                    
'UCID'     => 255,
                    
'ClickID'  => 7,
                    
'BStyle'   => ISB_DARK,
                    
'T'        => 55,
                    
'L'        => 60,
                    
'W'        => 80,
                    
'H'        => 10,
                    
'Text'     => '^3Race clean!');  
    
PIE_sendpacket($packet);
                          
    
$time microtime(true) + 6;
    
PIE_setcallback($time'killbutton'$packet['ClickID']); 
  }
  
function 
killbutton($id)
  {
    
PIE_sendpacket(array( 'Type'      => ISP_BFN,
                          
'SubType'   => BFN_DEL_BTN,
                          
'UCID'      => 255,
                          
'ClickID'   => $id));
  }  

?>

host.cfg: (set your own host/port/adminpass)

flags=0
host=1.2.3.4
port=54321
adminpass=secretpassword

Command line:

> pie tutorials\racestartmessage.php host.cfg

Tutorial 2: Hello player
Racon
S3 licensed
// [Hello player] /////////////////////////////////////////////////////////////

Now, let's make a program to greet every player that connects to the server
that we're on. We'll hook the NCN packet by defining a 'PIE_NCN' function and
use the PName field from the data parameter.

helloplayer.php:

<?php 

function PIE_NCN($data)
  {
    
PIE_say('Hello '.$data['PName']);
  }
  
?>

Command line:

> pie tutorials\helloplayer.php





// [Host hello player] ////////////////////////////////////////////////////////

Notice that this program is speaking as you - this is because the program is
in local mode. If we want a server to greet people, we must use host mode and
connect to the server instead of your client.

To connect to a server, we need the IP address, port number and admin
password of the server (these can be found in your host control panel), we
must add our IP address to the access whitelist (access control tab), and we
must set the correct flag settings (specifically, we must ensure that
ISF_LOCAL flag is not set). We can add these settings to our PIE script in two
ways:

Method 1: We'll add these settings to a config file, and use the original
helloplayer.php file unchanged. Please note that you cannot use constants in a
.cfg file. We will use the value 0 for 'flags'.

helloplayer.php file:


<?php 

function PIE_NCN($data)
  {
    
PIE_say('Hello '.$data['PName']);
  }
  
?>

host.cfg: (set your own host/port/adminpass)

flags=0
host=1.2.3.4
port=54321
adminpass=secretpassword

command line:

> pie tutorials\helloplayer.php host.cfg





Method 2: We'll copy the helloplayer.php file to hosthelloworld.php, and set
the settings we need with the 'PIE_settings' function. Here we can use our
InSim flag constants, if required.

hosthelloplayer.php: (set your own host/port/adminpass)


<?php 

function PIE_settings()
  {
    return array(
'flags'      => 0,
                 
'host'       => '1.2.3.4',
                 
'port'       => 54321,
                 
'adminpass'  => 'secretpassword');
  }

function 
PIE_NCN($data)
  {
    
PIE_say('Hello '.$data['PName']);
  }

?>

command line:

> pie tutorials\hosthelloplayer.php

Tutorial 1: Hello world
Racon
S3 licensed
// [Hello world] //////////////////////////////////////////////////////////////

The simplest program we can write for PIE is a 'hello world' program that
connects to your LFS client (local mode). If you are using the default InSim
port of 29999 and no admin password for your client, you don't need to set any
settings. (The admin password can be found in LFS's cfg.txt file as the 'Game
Admin' setting, or can be set inside LFS in the 'start new host' screen)

We'll define a function called 'PIE_start' (called as soon as the connection
is established), and within it we'll use the 'PIE_say' function (general
purpose 'talk' function) to send 'hello world' to chat.

helloworld.php:

<?php 

function PIE_start()
  {
    
PIE_say('Hello world');
  }

?>

Command line:

> pie tutorials\helloworld.php



Note that this program will continue to run after having said 'hello world'.
We can kill it using Ctrl-C in the console window it is running in, or
clicking the X button in the top right, but these are not ideal. Both may
leave the connection open until it times out, and both will cause any
'PIE_shutdown' function to be skipped.

In order to shut it down automatically, we can use the function 'PIE_kill'.
We'll also speak our message locally this time (other players don't see it),
by using the 'PIE_saylocal' function.

helloworldandquit.php:

<?php 

function PIE_start()
  {
    
PIE_saylocal('Hello local world');    
    
PIE_kill();
  }
  
function 
PIE_shutdown()
  {
    
PIE_say('Goodbye world');
  }

?>

Command line:

> pie tutorials\helloworldandquit.php

Tutorial 0: Introduction
Racon
S3 licensed
Note: You should read InSim.txt for an overview of how InSim works. PIE
handles a lot of things for you, but you need to know the difference between
your PLIDs and your UCIDs, which packets you can send/receive, what
instructions you can send, for a few examples.

Note for advanced programmers: please forgive the following
over-explanations, simplifications, terminology shortcuts and outright lies.
PIE is for all levels of coding ability, right down to the
only-just-beginning - the tutorials have to start there and build up! There
is a quick reference if you want a shortcut to the goodies.

// [Introduction] /////////////////////////////////////////////////////////////

PIE is designed to be give easy access to InSim functionality with the PHP
programming language (ver 7.2, CLI mode). It takes care of connection to InSim
(and optionally OutSim and OutGauge) and maintaining the connection, and calls
a user-defined function on receipt of any packet. It can be used to connect to
an LFS client (local mode) or an LFS server (host mode) and comes with some
basic commands and debugging.

PIE is a commandline executable that reads a PHP file (refered to as a PIE
script) and optionally a text configuration file. PIE then uses the settings
provided, or defaults, to initiate a connection to InSim. Once connected, PIE
will wake from sleep at the specified frequency to run a 'tick'. During this
tick, PIE will process any incoming packets, call any pending callback
functions, and return to sleep. PIE runs at between 5 and 50 ticks per second,
default 20.

PIE scripts consist of PHP functions that are called by PIE as appropriate,
such as at startup, on receipt of a packet, at a pre-specified time, etc.

There are functions available to do common tasks such as sending packets,
speaking to chat, etc., and a PIE object provides constantly-updated InSim
information and a data store.

Functions that are called on receipt of an InSim packet are called with a
parameter which consists of all the packet data, unpacked into an associative
array. Some packets with combined values have additional indexes for the
separated values, and all text fields have been made safe for windows (0 byte
stripped, raw SkinID bytes converted to SkinID text string).

PIE will attempt to run at the specified frequency by sleeping less after
longer tick, but you must still take care about the length of time it takes
your code to run. You have plenty of time to communicate with an online
database, for example, as long as your queries do not take longer to complete
than the length of your tick interval. PIE will not be able to process
packets, call callback functions etc., whilst waiting for script code. In
extreme cases, the InSim connection may timeout or the buffer may overflow.


// [Tutorial Overview] ////////////////////////////////////////////////////////

1) Hello world: (Connecting to local client; Sending messages to chat; Local chat; Shutting down PIE)
2) Hello player: (Accepting packets; Connecting to hosts; PIE cfg files)
3) Race start message: (Sending packets; Sending buttons; Callbacks)
4) Random lights: (PIE stored values; Debugging)
5) No-repair reset: (PIE commands; PIE data)
6) Headsup: (OutGauge; File logging)
7) Object info: (Layout objects; Button clicks; Multiple buttons)
Last edited by Racon, .
Racon
S3 licensed
Last edited by Racon, .
Racon
S3 licensed
Last edited by Racon, .
Racon
S3 licensed
There's an experimental option in the newest test patch (https://www.lfs.net/forum/thread/102117), it would be good for Scawen to hear from as many people who suffer this problem as possible.

Quote :- Options... Misc... HTTP buffer test [EXPERIMENTAL]

Racon
S3 licensed
No, private agreement means they have given you permission - mod reviewers will check with the author/owner.
FGED GREDG RDFGDR GSFDG