Basic Signal Scripting - Train Simulator Developer Documentation
Basic Signal Scripting - Train Simulator Developer Documentation
Train
Simulator
Developer
Documentation
NAVIGATION
Reference Manual > Signalling Guide > Train Simulator Signalling >
HOME
▼ CONTENT BASICS
SIGNAL DEBUGGING
AUDIO
Shunt exit signals tell a driver which way the junction ahead of the signal is set. If the junction is
▼ SCRIPTING FUNCTION REFERENCE ready for a train to drive over it, the lights are on. If the junction is set against you (in which
case driving over it would derail the train), the lights are o .
▼ TS NEW FEATURES
DOWNLOADS
In Train Simulator, all of this behaviour is controlled by the script that was referenced in the
signal's blueprint at \RailNetwork\signals\UK Colour Light\UK ShuntSig Exit Head.lua. This section
explains how this works.
Script Functions
A signal script is made up of a series of functions that are called either by the game code or by
other functions within the script. A function de nition looks something like this:
function MyFunction()
end
The shunt exit signal is a very simple case, as all it needs to do is keep track of the state of the
junction(s) it spans, and switch its lights on or o depending on whether the junction is
connected. The following sections describe these functions.
Initialise
Syntax: Initialise()
Every signal must have an Initialise() function, which is called by the game code when the signal
is rst activated as the route loads. Here you set up any information the script needs to know
about this signal and de ne any global constants and variables you want to use elsewhere in
the script.
-- INITIALISE
function Initialise()
-- Tells the game to do an update tick once the route finishes loading
Call( "BeginUpdate" )
end
First, several constants are de ned. These represent numbers that are used in messages sent
between signal scripts and the game code. Rather than use the numbers in the scripts, it is
better to give them an easy-to-remember name so that you can see at a glance what the script
is doing at each stage. By convention, all of Train Simulator's constants have names that are
written ENTIRELY_IN_CAPITALS.
Next two global variables are de ned - gConnectedLink (which will be used to keep track of
whether the junction beyond this signal is connected) and gInitialised (which starts as false and
is set to true once the route nishes loading). The global variables generally have names
beginning with a lower case “g” to indicate that they’re “global” (i.e. you can check and change
their value from any function in the script, not just the one they’re de ned in).
Note: A global variable is only global to this particular signal – each signal has its own
instance of the script running on it, so it is possible to have lots of signals of the same type
in a route, all running the same script, and they will all remember their own individual
states.
The nal step is to "Call" a function "BeginUpdate". BeginUpdate is not an LUA function de ned
in the signal script, but part of the main game code. Basically, Call sends a message to the
game engine telling it to run a particular code function - in this case, one called BeginUpdate,
which tells the game to start running the Update function.
Update
The Update function is a script function, so when we called BeginUpdate we were telling
the game code to start running this script function. The game will now keep running the Update
script function every frame until we tell it to stop. The "time" parameter is the game’s way of
telling the script how much time has passed since the game last did an Update. This is useful
for a variety of things, such as making lights ash and controlling animations and sound
e ects.
-- UPDATE
gInitialised = true
Call( "EndUpdate" )
end
Train Simulator will only start running the Update script function once the route has nished
loading, by which time the state of all the junctions is known by the game. As signals can span
several junctions, wait until they all know which way they’re set before calling the
OnJunctionStateChange script function to check if they’re connected. Otherwise, as the route
loads, the signal would keep checking whether it’s connected every time a junction between
the signal’s two links initialises.
Having set gInitialised to true (so you know the route has nished loading) and checked the
state of the junction, Call the code function "EndUpdate". As the name suggests, this tells the
game code to stop triggering the Update script function every frame. So the game will run
Update once to check whether the junction is connected, and then stop.
Obviously, any signal that calls BeginUpdate from anywhere in its script requires an Update
script function for the code to run, or an error will be generated and the signal won't work
properly.
OnJunctionStateChange
This function checks whether the line ahead is connected. Here’s how:
end
end
The words in brackets after "OnJunctionStateChange" are the names of parameters that the
function expects you to provide when you trigger it. These can be disregarded for the moment.
This script function is also very simple for the shunt exit signal. First, the script Calls a code
function "GetConnectedLink" and assigns the value that it returns to the global variable
gConnectedLink, so that the script knows which link (if any) is connected.
Again, this function requires a number of parameters – these are the values separated by
commas after it says “GetConnectedLink”. The rst parameter isn’t used, so leave it blank ("").
The second parameter (1) is the direction in which to check the line. This will almost always be
1 so that you will be looking forward or up the line beyond the signal. The last parameter (0) is
the link to start searching from.
This Call of GetConnectedLink will start at the signal’s link 0 and look up the line until it reaches a
broken junction, the end of the line, or another link belonging to this signal. Then it lets you
know which link (if any) is connected. As the shunt exit signal only has two links (0 and 1), the
value it sends back to the script is either 1 (if all the junctions between the two links are set
ready for you to drive past the signal) or -1 (if any of the junctions between the two links is set
against the train, blocking its path).
Once the script knows whether the junction is connected, it sets the signal to the appropriate
state by Calling two more code functions:
Set2DMapSignalState sets the colour that the signal appears on the 2D map. BLOCKED will make
it appear as a red circle, CLEAR will make it turn green.
ActivateNode is used to switch a signal’s lights on and o . The rst parameter is the name of the
node to activate/deactivate (in this case, "mod_trk_shunt_lightsOn"), which is set in the 3D model
le for the signal. The second parameter is 0 (to switch the light o ) or 1 (to switch it on).
OnSignalMessage
This is another function that every signal script must contain. Signal messages are sent up and
down the track by trains, junctions and other signals to give a signal information about the
state of the route around it. Whenever one of those messages hits a signal’s link, the game
engine triggers the OnSignalMessage function for that signal.
OnSignalMessage’s parameters let the game code provide the script with information about the
message - what kind of message it is, whether there’s any other information attached to it
(parameter), which direction the message was travelling in when it hit the link (1 if it came from
in front, -1 if it came from behind), and the linkIndex of the link it was received by (in the case of
a shunt exit signal, that will be either 0 or 1). The arrow already placed on the links of the
signals shows you which direction the link is facing in. If a message arrives at the side with the
arrow on it, it’s coming from in front of the link.
There are only two messages a shunt exit signal cares about – RESET_SIGNAL_STATE
and JUNCTION_STATE_CHANGE. All other messages should be forwarded on in the direction in
which they were travelling, in case another signal further down the line is interested in them.
-- ON SIGNAL MESSAGE
-- Called when a message is received by one of this signal’s links
-- This message lets us know that a junction has just been switched
elseif (message == JUNCTION_STATE_CHANGE) then
end
end
If the message is RESET_SIGNAL_STATE, the game is letting you know that you need to reset the
signal, as the player has just reloaded a saved position or returned to the game from the
scenario editor. This can be done by Calling the Initialise script function again. Note that this
message is sent directly to every signal in the route by the game engine, so there is no need to
forward it on.
If the message is JUNCTION_STATE_CHANGE, check that the message arrived on link 0. As this
type of message is sent by the junction itself when it switches. If it came from a junction that’s
between two links it must arrive at link 0 from in front. If the message was received by link 1
instead, it must have come from another junction further up the line that is irrelevant. Ignore
the message unless it came with its parameter value set to “0” (indicating that the junction has
now nished switching).
When sure the JUNCTION_STATE_CHANGE message is from a junction you are interested in,
trigger the OnJunctionStateChange script function. Now the parameters that are passed to that
function make more sense. "Junction_state" should always be 0, as it’s con rming that the
junction has nishing switching - if it was still in motion, neither track would be connected to
the junction and there wouldn’t be any point in checking its state. "Parameter" is no longer used
and should always be left blank. “Direction” is also obsolete and should be left as 1. Finally,
"linkIndex" is the link that received the junction state change message (and therefore the link
that is needed to look ahead to see if the junction that just switched is connected). For any
normal signal, this will always be 0.
If the message is of any other type, the shunt signal isn’t interested in it, so it just forwards it on
from the link it arrived at. This is done by Calling the SendSignalMessage code function. It takes
all the same parameters as OnSignalMessage, plus an extra one. The rst is the type of message,
the second is the parameter containing any additional information about the message, the
third is the direction the message should be sent in (note that this value is reversed – if the
message arrived from in front it should be sent backwards, which is direction -1, and vice
versa), and the last parameter is the linkIndex from which to send the message.
The fourth parameter (the extra 1 between direction and linkIndex) controls which signals can
receive this message. This should almost always be 1, which means that only signal links which
are pointing in the same direction as the one the message is being sent from will receive the
message. If for some reason you wanted the message to be picked up only by signal links
facing in the opposite direction, use -1 instead.
OnConsistPass
The last function that every script must have is OnConsistPass. "Consist" is just another term for
a train so, as the name suggests, this script function is triggered by the game code whenever a
train passes a link belonging to the signal.
The shunt signal doesn’t care about trains, only about whether or not the line ahead of it is
connected. So although an OnConsistPass function
is necessary in the script, in this case, it doesn’t actually do anything:
-- ON CONSIST PASS
-- Shunt signals do not care about consist passes
function OnConsistPass( prevFrontDist, prevBackDist, frontDist, backDist,
linkIndex )
-- do nothing on consist pass
end
The shunt exit signal’s script consists of a single .lua le with all of those function de nitions in
it. If you look at the actual "UK ShuntSig Exit Head.lua" script le used by the real shunt signal
(it's available in RailNetwork\Signals\UK Colour Light) you’ll see that it’s slightly more complex
than the script shown here. However, the script functions above are all that's needed to make
a fully functional shunt signal.