<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.nimbyrails.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Admin</id>
	<title>NIMBY Rails Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.nimbyrails.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Admin"/>
	<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/Special:Contributions/Admin"/>
	<updated>2026-05-02T00:38:16Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.38.4</generator>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=566</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=566"/>
		<updated>2026-02-12T18:05:28Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used in game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration, integer division or arbitrary setting of pointers and references, and most data exposed to scripts is read-only, strictly enforced by the language. Any expression result which could result in an out of bounds or invalid memory access must be checked for validity, and the API design together with the type system enforces it.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
pub struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;SpeedTrap,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- VisMod? 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' ColonNAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Script&amp;lt;/code&amp;gt; (with restrictions)&lt;br /&gt;
&lt;br /&gt;
Structs extending game types for player extensions must be declared as &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt;. When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
To read struct objects from script code they must be looked up using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API. Therefore only functions provided with &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt; object (or a context object with contains &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt;) can look up these objects. But you can pass around &amp;lt;code&amp;gt;DB&amp;amp;amp;&amp;lt;/code&amp;gt; as a parameter without any lifetime restrictions, since it’s a purely read only API. This API also works for non-pub structs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= ctx.db.view&amp;amp;lt;Example&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    log(&amp;amp;quot;v = @&amp;amp;quot;, config.v);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;pub-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== pub structs ====&lt;br /&gt;
&lt;br /&gt;
As explained earlier, &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs are the user interface of your scripts. They are exposed in the UI as input forms, and their &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;s can give some control over this rendering. Conceptually they are owned by the player of the game as part of the game object database, by attaching them to a game model object in the database, not the script. Scripts do not have any capability to create, edit or delete objects of &amp;lt;code&amp;gt;pub struct&amp;lt;/code&amp;gt;s. It is always the player who decides when to create a new object of these structs by interacting in the UI. Scripts can then read, and only read, the content of these objects, by using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API presented earlier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs have a very powerful capability: they have limited support for forward schema evolution. This means that the script developer can add to, and reorder, fields in &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, and the game runtime will be able keep the contents of the other fields intact. This is very important to respect the input data by the player. If you rename &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs or their fields, or change their types, the player input data will be lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;non-pub-or-private-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Non-pub (or private) structs ====&lt;br /&gt;
&lt;br /&gt;
Non-&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, also called private structs, are conceptually owned by the script as a part of the simulation, not the player. Their contents are assumed to be a black box by the rest of the game. Scripts are allowed to create and modify objects of these structs during their execution, which are automatically deleted at the end of the simulation frame. It is also possible to attach these structs to existing game model objects to extend their lifetime beyond the current frame. In this case their lifetime becomes the same as the game object, and they can be retrieved in later frames for reading, deleted or overwritten as desired.&lt;br /&gt;
&lt;br /&gt;
Private structs ''do not support schema evolution''. Changing field types, field names, reordering of fields, even just adding new fields at the end, will always result in losing all existing attached objects of the given struct. Some operations like resetting the simulation will also erase attached objects, because they are considered simulation state, not player created objects.&lt;br /&gt;
&lt;br /&gt;
Private structs support dynamic memory allocation. All private struct definitions automatically create a &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; method for the struct:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct PrivData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let ro &amp;amp;amp;= ctx.db.view&amp;amp;lt;PrivData&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    let rw &amp;amp;amp;mut= ro.clone();&lt;br /&gt;
    rw.v = 100;&lt;br /&gt;
    let empty &amp;amp;amp;mut= PrivData::new();&lt;br /&gt;
    empty.v = 200;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The objects allocated by &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; are always deleted at the end of the current simulation frame. Their lifetime can be extended beyond the current frame by attaching them to a game object, like &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, so their lifetime becomes the same as the attached object. The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API has methods for attaching and erasing these object.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;host-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Host structs ====&lt;br /&gt;
&lt;br /&gt;
Many of the exposed game APIs are also based around structs. These structs do not follow any of the previous rules. Some have special capabilities, for example simple structs like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt; are ''value objects'': they can be copied and passed around like any &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; would. Some others are strictly locked down and serve as very little beyond a way to keep a pointer safe. In general, when working with game API structs, assume they are what would be called ''move only'' in C++. And NimbyScript has no move operator or semantics, so in essence assume they are immutable, immobile references, except when documented otherwise (like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As an aside, all script declared &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; or not) are also always ''move only'', and always “owned” by some external entity. This is why the APIs for their manipulation are always based on pointers and references, even for private structs. It is not possible to create plain, stack allocated values of script structs, or to use them as fields in structs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version:&lt;br /&gt;
&lt;br /&gt;
* Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
* Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums)&lt;br /&gt;
* For pub structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* For private structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In pub structs these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types. &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; will also display a small list editor. Keep in mind the correct type is &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;Vec&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types. It will be displayed as the input widget label.&lt;br /&gt;
* The &amp;lt;code&amp;gt;description&amp;lt;/code&amp;gt; meta field is accepted for all field types. It will be displayed as the input widget tooltip.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- 'let' BindBody 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- 'let' BindBody ';'&lt;br /&gt;
BindBody    &amp;amp;lt;- NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' 'let' BindBody BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;=' / '&amp;amp;gt;=' / '&amp;amp;lt;' / '&amp;amp;gt;'&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- UnaryExp (MulOp UnaryExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp? DotExp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' ColonFishNAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- ColonFishNAME '(' CallArgs? ')'&lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere pointer types cannot be dereferenced, therefore cannot be used in dot expressions. The exception is the built-in function &amp;lt;code&amp;gt;is_valid(ptr): bool&amp;lt;/code&amp;gt;, which is usable with any pointer type.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;extensions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Extensions =&lt;br /&gt;
&lt;br /&gt;
Extending game database struct data with &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt; can also be used to extend the game code. The mechanism to do so is to first declare a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;ing a game database object (with or without fields). Then create a specifically named and parametrized function which will be called by the game under certain situations, for certain kinds of objects.&lt;br /&gt;
&lt;br /&gt;
All extension functions take a &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter which is a reference to the struct which it is method of, called &amp;lt;code&amp;gt;Example&amp;lt;/code&amp;gt; in the following sections. Replace it with your struct name. The rest of the parameters are fixed and must be reproduced exactly as-is.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
Event functions are called as part of the core simulation engine. They are meant to be focused in features and quick to execute. These functions might be called thousands of times per simulation frame, including multiple redundant times. Their capability to change the simulation behavior is usually very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_check&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_check ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails, or if another script call returns &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_lookahead&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_lookahead ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_lookahead(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    train_distance: f64,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalLookaheadResult&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; function at regular intervals for each signal 15km ahead of the train path. It is called for all signals, until one of these conditions hold:&lt;br /&gt;
&lt;br /&gt;
* One of the signals path checks as &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;&lt;br /&gt;
* Another train is found&lt;br /&gt;
* The train stop is found&lt;br /&gt;
* 15km have been checked&lt;br /&gt;
&lt;br /&gt;
For both &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; signals, your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; will be called, and you can check the path find result in &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;, and the distance from the train in &amp;lt;code&amp;gt;train_distance&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; allows to set a maximum speed for the train, which goes into effect immediately. It must be expressed as m/s. This works from any distance and past any amount of signals between the train and the caller signal. If multiple signals in the lookahead path return a &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt;, the slowest speed is picked. If no &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt; is set, or it is 0, the result is ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; default value is 0, which is considered invalid and will be ignored. To stop the train at the signal implement &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_change_path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_change_path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_change_path(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The current path check result of this signal for the passed train is passed as &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;. This already includes any results from &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_pass_by&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_pass_by ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_pass_by(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; function on the exact simulation frame a train passes by the exact point of the signal on the track.&lt;br /&gt;
&lt;br /&gt;
This function has no return result. Instead, since it has a predictably low call rate compared to the other events, it is the only event function with access to the powerful &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_marker_reserved&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_marker_reserved ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given marker signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; any time the reservation check algorithm is tracing a path which goes over the marker signal, on any direction, giving it the chance to report an arbitrary train as the reserver of that point on the track.&lt;br /&gt;
&lt;br /&gt;
This signal has a potential huge call rate, and for this reason it is given very little access to the APIs. The intention is that all the state required by this signal is calculated somewhere else and attached to the signal as a private struct object, or to some object reachable from it. Don’t worry about filtering for the “same train” cases, this is automatically done.&lt;br /&gt;
&lt;br /&gt;
If no reservation is desired, use the &amp;lt;code&amp;gt;empty&amp;lt;/code&amp;gt; global method available in all &amp;lt;code&amp;gt;ID&amp;amp;lt;Class&amp;amp;gt;&amp;lt;/code&amp;gt; types: &amp;lt;code&amp;gt;return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {}&lt;br /&gt;
struct Owner {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; {&lt;br /&gt;
    // some other, more full featured script function has attached Owner to this signal,&lt;br /&gt;
    // or not, so we need to check first&lt;br /&gt;
    if let owner &amp;amp;amp;= db.view&amp;amp;lt;Owner&amp;amp;gt;(signal) {&lt;br /&gt;
        if is_valid(db.view(owner.train_id)) {&lt;br /&gt;
            return owner.train_id;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_texture_state&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_texture_state ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_texture_state(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    clock_us: i64,&lt;br /&gt;
    core_state: i64&lt;br /&gt;
): i64 { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment, when the game UI needs to query what is the current signal texture state index, it will call your &amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt;, with some potential caching to keep the call rate lower. In any case the call rate of this function is potentially very large when the user zooms out the map, so make sure to keep its code as efficient as possible. For this same reason it is given very little access to the APIs. &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; is the number of sim-microseconds since the current save was created, you can use it with the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; functions to make animations. For path signals, &amp;lt;code&amp;gt;core_state&amp;lt;/code&amp;gt; is the current result of the signal check (including scripts), and it is valued 0 for Pass and 1 for Stop; for all other signals it is always 0.&lt;br /&gt;
&lt;br /&gt;
The return value indicates which signal texture state is to be used. If it’s -1 or lower, the default algorithm will be used to select the texture index. If it’s 0 or larger, it will select the texture in the same order as the &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; lines in the &amp;lt;code&amp;gt;SignalTextures&amp;lt;/code&amp;gt;. Larger values than the number of states will be clamped to the last state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_setup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_setup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_setup(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ss: &amp;amp;amp;mut ShiftSetup&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when an unassigned train decides to lookup a new shift to run, it will first call &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The parameter &amp;lt;code&amp;gt;ss&amp;lt;/code&amp;gt; is both an input and output parameter. It is initialized with the current, relevant data for the given train state, and &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; can then change it, to influence which shifts will be considered by the shift selection algorithm. It can change the train position used for matching, the time used for matching, and disable the check for reservations. For matched shifts which do not correspond to the current train position, the Extrapolator system will automatically pathfind a temporary milestone for the train, like other path-changing features. &amp;lt;code&amp;gt;ShiftSetup::epoch_s&amp;lt;/code&amp;gt; allowed range is between minus one week and plus one week from the current simulation time, with values outside this range being clamped into it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_allow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_allow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_allow(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    run: &amp;amp;amp;Run,&lt;br /&gt;
    stop_idx: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    pose: &amp;amp;amp;Pose&lt;br /&gt;
): ShiftAllow { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when the shift selection algorithm fins a valid shift for the given train, it will call &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; with all the relevant data. The return of the function can then allow or deny the shift. If the shift is denied, the algorithm will resume immediately, trying other shifts&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are independent from each other, and can be used in any combination.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;linestop-event_line_stop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Line::Stop event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestStop extend Line::Stop {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestStop::event_line_stop(&lt;br /&gt;
    self: &amp;amp;amp;TestStop,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == LineStopEvent::Arrive {&lt;br /&gt;
        log(&amp;amp;quot;@ arrives @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ departs @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given line stop in the line editor. From that moment, when any train arrives or departs said line stop, &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LineStopEvent::Depart&amp;lt;/code&amp;gt; to distinguish between arrival and departure. Waypoints are only called for &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt;. Shift-less trains are also called.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;shift-event_shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Shift event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestShift extend Shift {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestShift::event_shift(&lt;br /&gt;
    self: &amp;amp;amp;TestShift,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == ShiftEvent::Assign {&lt;br /&gt;
        log(&amp;amp;quot;@ assigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ unassigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given schedule shift in the line editor. From that moment, when any train is assigned to the shift, or becomes unassigned from the shift, &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;ShiftEvent::Assign&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ShiftEvent::Unassign&amp;lt;/code&amp;gt; to distinguish between assignation and unassignation. The &amp;lt;code&amp;gt;Assign&amp;lt;/code&amp;gt; event is called just after &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been set up, so it already has all the shift and run information. The &amp;lt;code&amp;gt;Unassign&amp;lt;/code&amp;gt; event is called just before &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been cleared of all shift and run information so the script has access to as much information as possible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;global-events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Global events ==&lt;br /&gt;
&lt;br /&gt;
Like event functions of struct extensions, global events are called as part of the core simulation engine when a specific event occurs, but they are not associated to any struct. Instead they are public top level functions with the signature given in this document. Global event functions are always called if they exist in a script and the event occurs.&lt;br /&gt;
&lt;br /&gt;
=== global_event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn global_event_line_stop(&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    log(&amp;amp;quot;global_event_line_stop: @ on line @&amp;amp;quot;, train, line);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Arguments and conditions are identical to &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt;, except there is no &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter.&lt;br /&gt;
&lt;br /&gt;
=== global_event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn global_event_shift(&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    log(&amp;amp;quot;global_event_shift: @ on sched @&amp;amp;quot;, train, sched);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Arguments and conditions are identical to &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt;, except there is no &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;controllers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Controllers ==&lt;br /&gt;
&lt;br /&gt;
Controller functions are called at a low frame rate compared to the overall simulation, with an (unchangeable) rate of once in 6 sim-seconds. They do not need any specific event or trigger to run, other than their enforced timer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-control_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train control_train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct HateDepots extend Train {}&lt;br /&gt;
pub fn HateDepots::control_train(&lt;br /&gt;
    self: &amp;amp;amp;HateDepots,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    // train is already removed from the tracks, don't interfere with potential attempts at shift assignation&lt;br /&gt;
    if !is_valid(motion.presence.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is running a schedule, don't interfere&lt;br /&gt;
    if is_valid(motion.schedule_dispatch.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is present, but it is not running a schedule, so despawn it&lt;br /&gt;
    sc.queue_train_intervention(train);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The train motion engine will call train controllers in the multithreaded phase, as part of the regular train motion extrapolator, after all the C++ code is done for a frame for a particular train, but before any queued commands are executed. Command execution will only happen after all train controllers for a given frame are done. In other words, train controllers queue up work to be executed by the sim. They never directly change the sim in any way, allowing train controller execution to be fully parallel.&lt;br /&gt;
&lt;br /&gt;
After all controllers are run, and all their non-task commands are executed, and then tasks are executed. Read more about tasks later on. Any tasks with a deadline which expired in this frame a run at this time too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontroller-command-queue&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== SimController command queue ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; object implements an API to control the simulation, including modification of some parameters and behaviors. It is also responsible for attaching and erasing private struct data from game objects, on behalf of scripts. The execution of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; is based on a command queue. Every call queues a command and returns immediately to the script code, without making any changes to the game state. Therefore the game state never changes while the script code is running.&lt;br /&gt;
&lt;br /&gt;
Commands queued from events and &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt; are executed asynchronously, there is no guaranteed order of execution! You must prepare your code and data for this design. For stand alone tasks scripts commands are executed in order and in isolation. You can queue up tasks from event and control scripts when you need to guarantee data consistency beyond “pick a random winner”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SimpleSimController&amp;lt;/code&amp;gt; is a cut down version of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; for high frequency events like &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt;. The reference in the second part of this document lists which &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; functions are available in &amp;lt;code&amp;gt;SimpleSimController&amp;lt;/code&amp;gt;, and they work identically.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_intervention&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_intervention ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks, releases its schedule shift (if any), and deletes and refunds its pax (if any). No other cost other than pax refunds is issued. This function can be used as a general “despawn the train” feature, not just for exceptional circumstances.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_warp&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_warp ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks and repositions it at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, re-pathing it to its currently scheduled destination (if any), and setting its speed to 0. This is basically a train wormhole. The train keeps its shift and pax, if any.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_drive_to&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_drive_to ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Re-paths the train path to end at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, without any changes to its shift or pax (if any). It is possible for any future &amp;lt;code&amp;gt;queue_train_drive_to&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; to reset this path at any point, losing the destination. “Queue” here is used as part of the SimController API semantics, it does not mean the train keeps a queue of positions to reach. If the path is not interrupted and the train reaches &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; it will re-path itself towards its current scheduled stop, if it has any, or brake to a stop if unassigned. If &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; was also in the stop area set for its current scheduled stop it will also brake to stop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_attach&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_attach ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the attachment of the &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;existing.clone()&amp;lt;/code&amp;gt;) to the &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt;, which must be of one of the following types: &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attached objects can be accessed with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt; at some point in the future. If called from a controller function, the attached object will be accessible after all controller functions are done for a given frame. If called from a task, he attached object will be accessible immediately after the task returns, and before any other task is executed. In other words, tasks are transaction-like, in the sense they view an immutable snapshot of the game state, and any changes they queue are executed before any other task, and then visible from these other tasks.&lt;br /&gt;
&lt;br /&gt;
Attaching an object of a given private struct type when it already exists attached to a &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt; will overwrite it. This is how private data is updated from scripting: by using &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; to copy any existing data, modifying the copy, then calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; to replace the existing data. Therefore it is a good idea to keep your private structs small. Only one instance of a given private struct type can be attached to any particular model object, but you can attach as many different private struct types as you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_erase&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_erase ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the erasure of &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt;, which must obtained using with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt;. Trying to erase temporary objects (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;existing.clone()&amp;lt;/code&amp;gt;) is ignored. The execution of the queued erase commands is analog to the &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; case. In particular a sequences of attach and erase queued from controllers will produce undefined results (impossible to predict which attach and/or erase wins). For example multiple attach from a controller for the same model_obj and private struct type will implicitly pick a singular “winner” attach, but the script does not have any control over which one. Sequences of attach and erase queued from tasks are strictly ordered and isolated, so they produce consistent results, in the same order they were queued in the task script, without any concurrent changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task-and-simcontrollerqueue_task_at&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task and SimController::queue_task_at ===&lt;br /&gt;
&lt;br /&gt;
See [[#Control%20tasks|control tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task_event_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task_event_train ===&lt;br /&gt;
&lt;br /&gt;
See [[#Event%20tasks|event tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;control-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Control tasks ==&lt;br /&gt;
&lt;br /&gt;
Control tasks are a very special kind of command which allows scripts to dynamically queue “future work”, with privileged access to the sim. Scripts with access to &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; can call this function to queue up a task for future script execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; must be of a private struct type which implements &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example { ... }&lt;br /&gt;
pub fn Example::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
For example, a train controller script could decide it needs to delay some decision into a task for data consistency reasons (other controllers are running at the same time), and delegate into a task rather than directly calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ControlTrain extend Train { ... }&lt;br /&gt;
pub fn ControlTrain::control_train(&lt;br /&gt;
    self: &amp;amp;amp;ControlTrain,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    task.train_id = train.id;&lt;br /&gt;
    task.v = some_data_from_somewhere;&lt;br /&gt;
    task.prio = 42; // or something smarter, like from ControlTrain, other objects, etc.&lt;br /&gt;
    sc.queue_task(task);&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
struct Task {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
struct SomeData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
pub fn Task::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    let train &amp;amp;amp;= ctx.db.view(self.train_id) else { return; }&lt;br /&gt;
    if let existing &amp;amp;amp;= ctx.db.view&amp;amp;lt;SomeData&amp;amp;gt;(train) {&lt;br /&gt;
        if existing.prio &amp;amp;gt;= self.prio {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    let data = SomeData::new();&lt;br /&gt;
    data.v = self.v;&lt;br /&gt;
    data.prio = self.prio;&lt;br /&gt;
    sc.queue_attach(train, data);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the previous example, maybe &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; will be called multiple times because multiple &amp;lt;code&amp;gt;ControlTrain::control_train()&amp;lt;/code&amp;gt; instances queued objects of &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;, but each execution will be single threaded, and all its queued &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; commands will be executed just after the call is done and before any other &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; call (for &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; or any other struct type), therefore the algorithm to pick a winner based on an explicit priority works.&lt;br /&gt;
&lt;br /&gt;
As mentioned, task execution is single threaded. The game does not feature a real concurrent database, instead all concurrent access is bespoke and very carefully designed to avoid deadlocks and inconsistencies (this is much faster than a general purpose concurrent database). Scripts also run in this parallel system, but their access to the game state is carefully restricted as explained earlier. But in the end, scripts also need to modify data, and do so in a consistent way. Tasks solve this issue, but do so in the most pessimistic possible way, by being single threaded. Therefore script developers should use them in moderation. Consider the “random winner” semantics of control script queuing first, which are completely free performance wise, before deciding you need a task. It is often the case a concurrent problem reduces to “pick 0 or 1 winners, any winner, but never 2 or more” and the default queue semantics already provide that guarantee for attaching a specific model/private pair.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; is provided with &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt;, therefore it can queue tasks itself. But unlike controller queuing tasks, which are guaranteed to run on the same frame, tasks queued from tasks are guaranteed to ''not'' run on the same frame, on purpose. They are deliberately stored away and forced a delay of 6 sim-seconds. This is to avoid misuse of tasks, and infinite looping.&lt;br /&gt;
&lt;br /&gt;
This behavior might even be desirable in certain scripts, for example if you are developing some stateful signal system and you need some kind of “cleanup” task that makes sure some signal being owned by some train is still the focus of said train. You can deliberately queue tasks for future simulation frames with &amp;lt;code&amp;gt;queue_task_at&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;deadline&amp;lt;/code&amp;gt; is expressed as microseconds since the start of the current save world. You can obtain the current simulation frame &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; value with &amp;lt;code&amp;gt;Extrapolator::clock_us()&amp;lt;/code&amp;gt;, like in this example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;    // schedule task to run 10 sim-s from now&lt;br /&gt;
    sc.queue_task_at(task, ctx.extrapolator.clock_us() + 10000000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;event-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Event tasks ==&lt;br /&gt;
&lt;br /&gt;
Event tasks are a lightweight version of tasks which run when triggered by certain events. Unlike control tasks, event tasks do not have unlimited access to the sim. Instead the run under an &amp;lt;code&amp;gt;EventCtx&amp;lt;/code&amp;gt; like pub struct events, and run multithreaded, at the same time as the C++ code. Unlike the regular &amp;lt;code&amp;gt;event_*&amp;lt;/code&amp;gt; methods, event tasks are queued for execution by script code, not by UI player commands. The design idea of these tasks is to offer a more focused and efficient execution model than &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt;: they are executed immediately once the relevant event happens, in multithreaded context, rather than require passive polling which might even miss certain events and force execution of single thread code.&lt;br /&gt;
&lt;br /&gt;
Any function with a &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; parameter can queue an even task like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Task {...}&lt;br /&gt;
fn f(..., train: &amp;amp;amp;Train, sc: &amp;amp;amp;mut SimController) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    sc.queue_task_event_train(task, train, TaskEventTrain::StopDepart);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
On the next stop departure of the train the &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt; method will be called:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn Task::task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: TaskEventTrain,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == TaskEventTrain::StopDepart {&lt;br /&gt;
        log(&amp;amp;quot;@ departs&amp;amp;quot;, train);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Like control tasks, event tasks encapsulate a single call. If a series of calls are desired, the task can requeue itself by calling &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt;. Event tasks are limited to a maximum of 1 for every possible train-struct-event combination, to avoid leaks. Trying to queue again the same train-struct-event combination will overwrite any existing task. Only the train and motion are provided as parameters. The code can then drill into motion to extract any required information, like shift or line.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-controlctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ControlCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ControlCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    sim: &amp;amp;amp;Sim,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim controller scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects, and associated script stuct objects.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::track_pos_project(self: &amp;amp;amp;DB, pos: &amp;amp;amp;Pos, distance: f64): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return a track position separated by ‘distance’ meters from ‘pos’, in the direction of ‘pos’. If distance is negative it will be in the opposite direction. Can only follow the main track. Merges and dead ends will return a Pos a shorter distance away. Signals are ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view_self(self: &amp;amp;amp;DB): &amp;amp;amp;Script&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-eventctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type EventCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct EventCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim event handler scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line::Stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line::Stop {&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    cars_config: i32,&lt;br /&gt;
    dynamics: Train::Dynamics,&lt;br /&gt;
    hitched_by: Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    station_stop: std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt;,&lt;br /&gt;
    run_stop: std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
    run_dispatch: std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;,&lt;br /&gt;
    hitch: std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motioncachedhitcher&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::CachedHitcher ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::CachedHitcher {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionhitch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Hitch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Hitch {&lt;br /&gt;
    driver_train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    flip: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Train is being hitched by a driver train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
    flip: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionrundispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::RunDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::RunDispatch {&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a line run.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Motion::RunDispatch::current_stop(self: &amp;amp;amp;Motion::RunDispatch, line: &amp;amp;amp;Line): *Line::Stop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionrunstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::RunStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::RunStop {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its line run.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionstationstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::StationStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::StationStop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Schedule::view(self: &amp;amp;amp;Schedule, shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;): *Shift&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns a pointer to the shift, if it’s contained in this schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-script&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Script ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Script {&lt;br /&gt;
    id: ID&amp;amp;lt;Script&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Shift {&lt;br /&gt;
    id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::kind(self: &amp;amp;amp;Signal): mut SignalKind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the signal kind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Track::max_speed(self: &amp;amp;amp;Track): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the min(physical, manual setting) max speed of the track, in m/s.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
    as_purchased: Train::Dynamics,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-traindynamics&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train::Dynamics ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train::Dynamics {&lt;br /&gt;
    max_speed: f32,&lt;br /&gt;
    max_acceleration: f32,&lt;br /&gt;
    max_regular_braking: f32,&lt;br /&gt;
    max_emergency_braking: f32,&lt;br /&gt;
    max_tractive_effort: f32,&lt;br /&gt;
    total_power: f32,&lt;br /&gt;
    empty_mass: f32,&lt;br /&gt;
    length: f32,&lt;br /&gt;
    max_pax: i32,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vec&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;lt;Motion::CachedHitcher&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Hitch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;): *Motion::Hitch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;): *Motion::RunStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::StationStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt;&lt;br /&gt;
): *Motion::StationStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Script&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Shift&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Shift&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Shift&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciterator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;lt;Motion::CachedHitcher&amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator::next(&lt;br /&gt;
    self: &amp;amp;amp;mut Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator&lt;br /&gt;
): *Motion::CachedHitcher&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    idx: i64&lt;br /&gt;
): *Motion::CachedHitcher&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::clock_us(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current microseconds since the creation of this saved game. This is used as the timing root of the simulation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second since 1970-01-01:00:00:00.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_occupation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_reservation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying or reserving the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_occupying(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_reserving(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying or reserving the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
Probe a track position for train reservations and occupations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::view_last&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Extrapolator, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the last frame Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Seconds since 1970-01-01:00:00:00 for Monday 00:00:00 of the current week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestopevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type LineStopEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum LineStopEvent {&lt;br /&gt;
    Arrive,&lt;br /&gt;
    Depart,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
Advance the iterator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftallow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftAllow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftAllow {&lt;br /&gt;
    Allow,&lt;br /&gt;
    Deny,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftEvent {&lt;br /&gt;
    Assign,&lt;br /&gt;
    Unassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftsetup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftSetup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ShiftSetup {&lt;br /&gt;
    skip: bool,&lt;br /&gt;
    match_pos: bool,&lt;br /&gt;
    check_occupation: bool,&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores the context of a train shift lookup.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function wants to change the train path, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signallookaheadresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalLookaheadResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalLookaheadResult {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores extra information associated with the result of the signal lookahead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-sim&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Sim ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Sim {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of the simulation state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Sim::view&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Sim, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A proxy mutable API to the simulation engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    ev: TaskEventTrain&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_hitch(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    driver: &amp;amp;amp;Train,&lt;br /&gt;
    hitcher: &amp;amp;amp;Train,&lt;br /&gt;
    order: i64,&lt;br /&gt;
    flip: bool&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hitch a train to a driver train. The hitched train is emptied of pax and removed from the sim, while its cars are appended to the driver. The order parameter (from -1000 to 1000) determines the hitched train cars position: the driver train is always order 0, so negative values will put the hitch in front of the driver, and positive values behind it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(self: &amp;amp;amp;mut SimController, train: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_run_line(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    arrival_offset_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_configuration(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    config: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_presence_flip(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    flip: bool&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_stop_delay(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    delay_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add extra delay time to a stopped train that has a timed_stop component.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_unhitch(self: &amp;amp;amp;mut SimController, hitcher: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Remove the hitched state from a train. It will become an unspawned, unassigned train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simplesimcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimpleSimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimpleSimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A limited API version of SimController.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimpleSimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimpleSimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-taskeventtrain&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TaskEventTrain ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum TaskEventTrain {&lt;br /&gt;
    StopArrive,&lt;br /&gt;
    StopDepart,&lt;br /&gt;
    ShiftAssign,&lt;br /&gt;
    ShiftUnassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=565</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=565"/>
		<updated>2026-02-07T17:23:07Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used in game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration, integer division or arbitrary setting of pointers and references, and most data exposed to scripts is read-only, strictly enforced by the language. Any expression result which could result in an out of bounds or invalid memory access must be checked for validity, and the API design together with the type system enforces it.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
pub struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;SpeedTrap,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- VisMod? 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' ColonNAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Script&amp;lt;/code&amp;gt; (with restrictions)&lt;br /&gt;
&lt;br /&gt;
Structs extending game types for player extensions must be declared as &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt;. When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
To read struct objects from script code they must be looked up using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API. Therefore only functions provided with &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt; object (or a context object with contains &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt;) can look up these objects. But you can pass around &amp;lt;code&amp;gt;DB&amp;amp;amp;&amp;lt;/code&amp;gt; as a parameter without any lifetime restrictions, since it’s a purely read only API. This API also works for non-pub structs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= ctx.db.view&amp;amp;lt;Example&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    log(&amp;amp;quot;v = @&amp;amp;quot;, config.v);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;pub-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== pub structs ====&lt;br /&gt;
&lt;br /&gt;
As explained earlier, &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs are the user interface of your scripts. They are exposed in the UI as input forms, and their &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;s can give some control over this rendering. Conceptually they are owned by the player of the game as part of the game object database, by attaching them to a game model object in the database, not the script. Scripts do not have any capability to create, edit or delete objects of &amp;lt;code&amp;gt;pub struct&amp;lt;/code&amp;gt;s. It is always the player who decides when to create a new object of these structs by interacting in the UI. Scripts can then read, and only read, the content of these objects, by using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API presented earlier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs have a very powerful capability: they have limited support for forward schema evolution. This means that the script developer can add to, and reorder, fields in &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, and the game runtime will be able keep the contents of the other fields intact. This is very important to respect the input data by the player. If you rename &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs or their fields, or change their types, the player input data will be lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;non-pub-or-private-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Non-pub (or private) structs ====&lt;br /&gt;
&lt;br /&gt;
Non-&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, also called private structs, are conceptually owned by the script as a part of the simulation, not the player. Their contents are assumed to be a black box by the rest of the game. Scripts are allowed to create and modify objects of these structs during their execution, which are automatically deleted at the end of the simulation frame. It is also possible to attach these structs to existing game model objects to extend their lifetime beyond the current frame. In this case their lifetime becomes the same as the game object, and they can be retrieved in later frames for reading, deleted or overwritten as desired.&lt;br /&gt;
&lt;br /&gt;
Private structs ''do not support schema evolution''. Changing field types, field names, reordering of fields, even just adding new fields at the end, will always result in losing all existing attached objects of the given struct. Some operations like resetting the simulation will also erase attached objects, because they are considered simulation state, not player created objects.&lt;br /&gt;
&lt;br /&gt;
Private structs support dynamic memory allocation. All private struct definitions automatically create a &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; method for the struct:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct PrivData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let ro &amp;amp;amp;= ctx.db.view&amp;amp;lt;PrivData&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    let rw &amp;amp;amp;mut= ro.clone();&lt;br /&gt;
    rw.v = 100;&lt;br /&gt;
    let empty &amp;amp;amp;mut= PrivData::new();&lt;br /&gt;
    empty.v = 200;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The objects allocated by &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; are always deleted at the end of the current simulation frame. Their lifetime can be extended beyond the current frame by attaching them to a game object, like &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, so their lifetime becomes the same as the attached object. The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API has methods for attaching and erasing these object.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;host-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Host structs ====&lt;br /&gt;
&lt;br /&gt;
Many of the exposed game APIs are also based around structs. These structs do not follow any of the previous rules. Some have special capabilities, for example simple structs like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt; are ''value objects'': they can be copied and passed around like any &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; would. Some others are strictly locked down and serve as very little beyond a way to keep a pointer safe. In general, when working with game API structs, assume they are what would be called ''move only'' in C++. And NimbyScript has no move operator or semantics, so in essence assume they are immutable, immobile references, except when documented otherwise (like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As an aside, all script declared &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; or not) are also always ''move only'', and always “owned” by some external entity. This is why the APIs for their manipulation are always based on pointers and references, even for private structs. It is not possible to create plain, stack allocated values of script structs, or to use them as fields in structs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version:&lt;br /&gt;
&lt;br /&gt;
* Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
* Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums)&lt;br /&gt;
* For pub structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* For private structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In pub structs these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types. &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; will also display a small list editor. Keep in mind the correct type is &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;Vec&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types. It will be displayed as the input widget label.&lt;br /&gt;
* The &amp;lt;code&amp;gt;description&amp;lt;/code&amp;gt; meta field is accepted for all field types. It will be displayed as the input widget tooltip.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- 'let' BindBody 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- 'let' BindBody ';'&lt;br /&gt;
BindBody    &amp;amp;lt;- NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' 'let' BindBody BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- ColonNAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere pointer types cannot be dereferenced, therefore cannot be used in dot expressions. The exception is the built-in function &amp;lt;code&amp;gt;is_valid(ptr): bool&amp;lt;/code&amp;gt;, which is usable with any pointer type.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;extensions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Extensions =&lt;br /&gt;
&lt;br /&gt;
Extending game database struct data with &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt; can also be used to extend the game code. The mechanism to do so is to first declare a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;ing a game database object (with or without fields). Then create a specifically named and parametrized function which will be called by the game under certain situations, for certain kinds of objects.&lt;br /&gt;
&lt;br /&gt;
All extension functions take a &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter which is a reference to the struct which it is method of, called &amp;lt;code&amp;gt;Example&amp;lt;/code&amp;gt; in the following sections. Replace it with your struct name. The rest of the parameters are fixed and must be reproduced exactly as-is.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
Event functions are called as part of the core simulation engine. They are meant to be focused in features and quick to execute. These functions might be called thousands of times per simulation frame, including multiple redundant times. Their capability to change the simulation behavior is usually very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_check&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_check ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails, or if another script call returns &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_lookahead&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_lookahead ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_lookahead(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    train_distance: f64,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalLookaheadResult&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; function at regular intervals for each signal 15km ahead of the train path. It is called for all signals, until one of these conditions hold:&lt;br /&gt;
&lt;br /&gt;
* One of the signals path checks as &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;&lt;br /&gt;
* Another train is found&lt;br /&gt;
* The train stop is found&lt;br /&gt;
* 15km have been checked&lt;br /&gt;
&lt;br /&gt;
For both &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; signals, your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; will be called, and you can check the path find result in &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;, and the distance from the train in &amp;lt;code&amp;gt;train_distance&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; allows to set a maximum speed for the train, which goes into effect immediately. It must be expressed as m/s. This works from any distance and past any amount of signals between the train and the caller signal. If multiple signals in the lookahead path return a &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt;, the slowest speed is picked. If no &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt; is set, or it is 0, the result is ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; default value is 0, which is considered invalid and will be ignored. To stop the train at the signal implement &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_change_path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_change_path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_change_path(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The current path check result of this signal for the passed train is passed as &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;. This already includes any results from &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_pass_by&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_pass_by ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_pass_by(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; function on the exact simulation frame a train passes by the exact point of the signal on the track.&lt;br /&gt;
&lt;br /&gt;
This function has no return result. Instead, since it has a predictably low call rate compared to the other events, it is the only event function with access to the powerful &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_marker_reserved&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_marker_reserved ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given marker signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; any time the reservation check algorithm is tracing a path which goes over the marker signal, on any direction, giving it the chance to report an arbitrary train as the reserver of that point on the track.&lt;br /&gt;
&lt;br /&gt;
This signal has a potential huge call rate, and for this reason it is given very little access to the APIs. The intention is that all the state required by this signal is calculated somewhere else and attached to the signal as a private struct object, or to some object reachable from it. Don’t worry about filtering for the “same train” cases, this is automatically done.&lt;br /&gt;
&lt;br /&gt;
If no reservation is desired, use the &amp;lt;code&amp;gt;empty&amp;lt;/code&amp;gt; global method available in all &amp;lt;code&amp;gt;ID&amp;amp;lt;Class&amp;amp;gt;&amp;lt;/code&amp;gt; types: &amp;lt;code&amp;gt;return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {}&lt;br /&gt;
struct Owner {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; {&lt;br /&gt;
    // some other, more full featured script function has attached Owner to this signal,&lt;br /&gt;
    // or not, so we need to check first&lt;br /&gt;
    if let owner &amp;amp;amp;= db.view&amp;amp;lt;Owner&amp;amp;gt;(signal) {&lt;br /&gt;
        if is_valid(db.view(owner.train_id)) {&lt;br /&gt;
            return owner.train_id;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_texture_state&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_texture_state ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_texture_state(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    clock_us: i64,&lt;br /&gt;
    core_state: i64&lt;br /&gt;
): i64 { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment, when the game UI needs to query what is the current signal texture state index, it will call your &amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt;, with some potential caching to keep the call rate lower. In any case the call rate of this function is potentially very large when the user zooms out the map, so make sure to keep its code as efficient as possible. For this same reason it is given very little access to the APIs. &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; is the number of sim-microseconds since the current save was created, you can use it with the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; functions to make animations. For path signals, &amp;lt;code&amp;gt;core_state&amp;lt;/code&amp;gt; is the current result of the signal check (including scripts), and it is valued 0 for Pass and 1 for Stop; for all other signals it is always 0.&lt;br /&gt;
&lt;br /&gt;
The return value indicates which signal texture state is to be used. If it’s -1 or lower, the default algorithm will be used to select the texture index. If it’s 0 or larger, it will select the texture in the same order as the &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; lines in the &amp;lt;code&amp;gt;SignalTextures&amp;lt;/code&amp;gt;. Larger values than the number of states will be clamped to the last state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_setup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_setup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_setup(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ss: &amp;amp;amp;mut ShiftSetup&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when an unassigned train decides to lookup a new shift to run, it will first call &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The parameter &amp;lt;code&amp;gt;ss&amp;lt;/code&amp;gt; is both an input and output parameter. It is initialized with the current, relevant data for the given train state, and &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; can then change it, to influence which shifts will be considered by the shift selection algorithm. It can change the train position used for matching, the time used for matching, and disable the check for reservations. For matched shifts which do not correspond to the current train position, the Extrapolator system will automatically pathfind a temporary milestone for the train, like other path-changing features. &amp;lt;code&amp;gt;ShiftSetup::epoch_s&amp;lt;/code&amp;gt; allowed range is between minus one week and plus one week from the current simulation time, with values outside this range being clamped into it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_allow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_allow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_allow(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    run: &amp;amp;amp;Run,&lt;br /&gt;
    stop_idx: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    pose: &amp;amp;amp;Pose&lt;br /&gt;
): ShiftAllow { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when the shift selection algorithm fins a valid shift for the given train, it will call &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; with all the relevant data. The return of the function can then allow or deny the shift. If the shift is denied, the algorithm will resume immediately, trying other shifts&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are independent from each other, and can be used in any combination.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;linestop-event_line_stop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Line::Stop event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestStop extend Line::Stop {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestStop::event_line_stop(&lt;br /&gt;
    self: &amp;amp;amp;TestStop,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == LineStopEvent::Arrive {&lt;br /&gt;
        log(&amp;amp;quot;@ arrives @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ departs @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given line stop in the line editor. From that moment, when any train arrives or departs said line stop, &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LineStopEvent::Depart&amp;lt;/code&amp;gt; to distinguish between arrival and departure. Waypoints are only called for &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt;. Shift-less trains are also called.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;shift-event_shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Shift event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestShift extend Shift {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestShift::event_shift(&lt;br /&gt;
    self: &amp;amp;amp;TestShift,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == ShiftEvent::Assign {&lt;br /&gt;
        log(&amp;amp;quot;@ assigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ unassigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given schedule shift in the line editor. From that moment, when any train is assigned to the shift, or becomes unassigned from the shift, &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;ShiftEvent::Assign&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ShiftEvent::Unassign&amp;lt;/code&amp;gt; to distinguish between assignation and unassignation. The &amp;lt;code&amp;gt;Assign&amp;lt;/code&amp;gt; event is called just after &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been set up, so it already has all the shift and run information. The &amp;lt;code&amp;gt;Unassign&amp;lt;/code&amp;gt; event is called just before &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been cleared of all shift and run information so the script has access to as much information as possible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;global-events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Global events ==&lt;br /&gt;
&lt;br /&gt;
Like event functions of struct extensions, global events are called as part of the core simulation engine when a specific event occurs, but they are not associated to any struct. Instead they are public top level functions with the signature given in this document. Global event functions are always called if they exist in a script and the event occurs.&lt;br /&gt;
&lt;br /&gt;
=== global_event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn global_event_line_stop(&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    log(&amp;amp;quot;global_event_line_stop: @ on line @&amp;amp;quot;, train, line);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Arguments and conditions are identical to &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt;, except there is no &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter.&lt;br /&gt;
&lt;br /&gt;
=== global_event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn global_event_shift(&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    log(&amp;amp;quot;global_event_shift: @ on sched @&amp;amp;quot;, train, sched);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Arguments and conditions are identical to &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt;, except there is no &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;controllers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Controllers ==&lt;br /&gt;
&lt;br /&gt;
Controller functions are called at a low frame rate compared to the overall simulation, with an (unchangeable) rate of once in 6 sim-seconds. They do not need any specific event or trigger to run, other than their enforced timer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-control_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train control_train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct HateDepots extend Train {}&lt;br /&gt;
pub fn HateDepots::control_train(&lt;br /&gt;
    self: &amp;amp;amp;HateDepots,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    // train is already removed from the tracks, don't interfere with potential attempts at shift assignation&lt;br /&gt;
    if !is_valid(motion.presence.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is running a schedule, don't interfere&lt;br /&gt;
    if is_valid(motion.schedule_dispatch.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is present, but it is not running a schedule, so despawn it&lt;br /&gt;
    sc.queue_train_intervention(train);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The train motion engine will call train controllers in the multithreaded phase, as part of the regular train motion extrapolator, after all the C++ code is done for a frame for a particular train, but before any queued commands are executed. Command execution will only happen after all train controllers for a given frame are done. In other words, train controllers queue up work to be executed by the sim. They never directly change the sim in any way, allowing train controller execution to be fully parallel.&lt;br /&gt;
&lt;br /&gt;
After all controllers are run, and all their non-task commands are executed, and then tasks are executed. Read more about tasks later on. Any tasks with a deadline which expired in this frame a run at this time too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontroller-command-queue&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== SimController command queue ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; object implements an API to control the simulation, including modification of some parameters and behaviors. It is also responsible for attaching and erasing private struct data from game objects, on behalf of scripts. The execution of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; is based on a command queue. Every call queues a command and returns immediately to the script code, without making any changes to the game state. Therefore the game state never changes while the script code is running.&lt;br /&gt;
&lt;br /&gt;
Commands queued from events and &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt; are executed asynchronously, there is no guaranteed order of execution! You must prepare your code and data for this design. For stand alone tasks scripts commands are executed in order and in isolation. You can queue up tasks from event and control scripts when you need to guarantee data consistency beyond “pick a random winner”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SimpleSimController&amp;lt;/code&amp;gt; is a cut down version of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; for high frequency events like &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt;. The reference in the second part of this document lists which &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; functions are available in &amp;lt;code&amp;gt;SimpleSimController&amp;lt;/code&amp;gt;, and they work identically.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_intervention&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_intervention ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks, releases its schedule shift (if any), and deletes and refunds its pax (if any). No other cost other than pax refunds is issued. This function can be used as a general “despawn the train” feature, not just for exceptional circumstances.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_warp&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_warp ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks and repositions it at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, re-pathing it to its currently scheduled destination (if any), and setting its speed to 0. This is basically a train wormhole. The train keeps its shift and pax, if any.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_drive_to&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_drive_to ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Re-paths the train path to end at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, without any changes to its shift or pax (if any). It is possible for any future &amp;lt;code&amp;gt;queue_train_drive_to&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; to reset this path at any point, losing the destination. “Queue” here is used as part of the SimController API semantics, it does not mean the train keeps a queue of positions to reach. If the path is not interrupted and the train reaches &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; it will re-path itself towards its current scheduled stop, if it has any, or brake to a stop if unassigned. If &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; was also in the stop area set for its current scheduled stop it will also brake to stop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_attach&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_attach ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the attachment of the &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;existing.clone()&amp;lt;/code&amp;gt;) to the &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt;, which must be of one of the following types: &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attached objects can be accessed with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt; at some point in the future. If called from a controller function, the attached object will be accessible after all controller functions are done for a given frame. If called from a task, he attached object will be accessible immediately after the task returns, and before any other task is executed. In other words, tasks are transaction-like, in the sense they view an immutable snapshot of the game state, and any changes they queue are executed before any other task, and then visible from these other tasks.&lt;br /&gt;
&lt;br /&gt;
Attaching an object of a given private struct type when it already exists attached to a &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt; will overwrite it. This is how private data is updated from scripting: by using &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; to copy any existing data, modifying the copy, then calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; to replace the existing data. Therefore it is a good idea to keep your private structs small. Only one instance of a given private struct type can be attached to any particular model object, but you can attach as many different private struct types as you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_erase&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_erase ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the erasure of &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt;, which must obtained using with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt;. Trying to erase temporary objects (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;existing.clone()&amp;lt;/code&amp;gt;) is ignored. The execution of the queued erase commands is analog to the &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; case. In particular a sequences of attach and erase queued from controllers will produce undefined results (impossible to predict which attach and/or erase wins). For example multiple attach from a controller for the same model_obj and private struct type will implicitly pick a singular “winner” attach, but the script does not have any control over which one. Sequences of attach and erase queued from tasks are strictly ordered and isolated, so they produce consistent results, in the same order they were queued in the task script, without any concurrent changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task-and-simcontrollerqueue_task_at&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task and SimController::queue_task_at ===&lt;br /&gt;
&lt;br /&gt;
See [[#Control%20tasks|control tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task_event_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task_event_train ===&lt;br /&gt;
&lt;br /&gt;
See [[#Event%20tasks|event tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;control-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Control tasks ==&lt;br /&gt;
&lt;br /&gt;
Control tasks are a very special kind of command which allows scripts to dynamically queue “future work”, with privileged access to the sim. Scripts with access to &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; can call this function to queue up a task for future script execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; must be of a private struct type which implements &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example { ... }&lt;br /&gt;
pub fn Example::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
For example, a train controller script could decide it needs to delay some decision into a task for data consistency reasons (other controllers are running at the same time), and delegate into a task rather than directly calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ControlTrain extend Train { ... }&lt;br /&gt;
pub fn ControlTrain::control_train(&lt;br /&gt;
    self: &amp;amp;amp;ControlTrain,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    task.train_id = train.id;&lt;br /&gt;
    task.v = some_data_from_somewhere;&lt;br /&gt;
    task.prio = 42; // or something smarter, like from ControlTrain, other objects, etc.&lt;br /&gt;
    sc.queue_task(task);&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
struct Task {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
struct SomeData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
pub fn Task::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    let train &amp;amp;amp;= ctx.db.view(self.train_id) else { return; }&lt;br /&gt;
    if let existing &amp;amp;amp;= ctx.db.view&amp;amp;lt;SomeData&amp;amp;gt;(train) {&lt;br /&gt;
        if existing.prio &amp;amp;gt;= self.prio {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    let data = SomeData::new();&lt;br /&gt;
    data.v = self.v;&lt;br /&gt;
    data.prio = self.prio;&lt;br /&gt;
    sc.queue_attach(train, data);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the previous example, maybe &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; will be called multiple times because multiple &amp;lt;code&amp;gt;ControlTrain::control_train()&amp;lt;/code&amp;gt; instances queued objects of &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;, but each execution will be single threaded, and all its queued &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; commands will be executed just after the call is done and before any other &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; call (for &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; or any other struct type), therefore the algorithm to pick a winner based on an explicit priority works.&lt;br /&gt;
&lt;br /&gt;
As mentioned, task execution is single threaded. The game does not feature a real concurrent database, instead all concurrent access is bespoke and very carefully designed to avoid deadlocks and inconsistencies (this is much faster than a general purpose concurrent database). Scripts also run in this parallel system, but their access to the game state is carefully restricted as explained earlier. But in the end, scripts also need to modify data, and do so in a consistent way. Tasks solve this issue, but do so in the most pessimistic possible way, by being single threaded. Therefore script developers should use them in moderation. Consider the “random winner” semantics of control script queuing first, which are completely free performance wise, before deciding you need a task. It is often the case a concurrent problem reduces to “pick 0 or 1 winners, any winner, but never 2 or more” and the default queue semantics already provide that guarantee for attaching a specific model/private pair.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; is provided with &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt;, therefore it can queue tasks itself. But unlike controller queuing tasks, which are guaranteed to run on the same frame, tasks queued from tasks are guaranteed to ''not'' run on the same frame, on purpose. They are deliberately stored away and forced a delay of 6 sim-seconds. This is to avoid misuse of tasks, and infinite looping.&lt;br /&gt;
&lt;br /&gt;
This behavior might even be desirable in certain scripts, for example if you are developing some stateful signal system and you need some kind of “cleanup” task that makes sure some signal being owned by some train is still the focus of said train. You can deliberately queue tasks for future simulation frames with &amp;lt;code&amp;gt;queue_task_at&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;deadline&amp;lt;/code&amp;gt; is expressed as microseconds since the start of the current save world. You can obtain the current simulation frame &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; value with &amp;lt;code&amp;gt;Extrapolator::clock_us()&amp;lt;/code&amp;gt;, like in this example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;    // schedule task to run 10 sim-s from now&lt;br /&gt;
    sc.queue_task_at(task, ctx.extrapolator.clock_us() + 10000000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;event-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Event tasks ==&lt;br /&gt;
&lt;br /&gt;
Event tasks are a lightweight version of tasks which run when triggered by certain events. Unlike control tasks, event tasks do not have unlimited access to the sim. Instead the run under an &amp;lt;code&amp;gt;EventCtx&amp;lt;/code&amp;gt; like pub struct events, and run multithreaded, at the same time as the C++ code. Unlike the regular &amp;lt;code&amp;gt;event_*&amp;lt;/code&amp;gt; methods, event tasks are queued for execution by script code, not by UI player commands. The design idea of these tasks is to offer a more focused and efficient execution model than &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt;: they are executed immediately once the relevant event happens, in multithreaded context, rather than require passive polling which might even miss certain events and force execution of single thread code.&lt;br /&gt;
&lt;br /&gt;
Any function with a &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; parameter can queue an even task like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Task {...}&lt;br /&gt;
fn f(..., train: &amp;amp;amp;Train, sc: &amp;amp;amp;mut SimController) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    sc.queue_task_event_train(task, train, TaskEventTrain::StopDepart);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
On the next stop departure of the train the &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt; method will be called:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn Task::task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: TaskEventTrain,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == TaskEventTrain::StopDepart {&lt;br /&gt;
        log(&amp;amp;quot;@ departs&amp;amp;quot;, train);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Like control tasks, event tasks encapsulate a single call. If a series of calls are desired, the task can requeue itself by calling &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt;. Event tasks are limited to a maximum of 1 for every possible train-struct-event combination, to avoid leaks. Trying to queue again the same train-struct-event combination will overwrite any existing task. Only the train and motion are provided as parameters. The code can then drill into motion to extract any required information, like shift or line.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-controlctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ControlCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ControlCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    sim: &amp;amp;amp;Sim,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim controller scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects, and associated script stuct objects.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::track_pos_project(self: &amp;amp;amp;DB, pos: &amp;amp;amp;Pos, distance: f64): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return a track position separated by ‘distance’ meters from ‘pos’, in the direction of ‘pos’. If distance is negative it will be in the opposite direction. Can only follow the main track. Merges and dead ends will return a Pos a shorter distance away. Signals are ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view_self(self: &amp;amp;amp;DB): &amp;amp;amp;Script&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-eventctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type EventCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct EventCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim event handler scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line::Stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line::Stop {&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    cars_config: i32,&lt;br /&gt;
    dynamics: Train::Dynamics,&lt;br /&gt;
    hitched_by: Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    station_stop: std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt;,&lt;br /&gt;
    run_stop: std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
    run_dispatch: std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;,&lt;br /&gt;
    hitch: std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motioncachedhitcher&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::CachedHitcher ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::CachedHitcher {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionhitch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Hitch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Hitch {&lt;br /&gt;
    driver_train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    flip: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Train is being hitched by a driver train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
    flip: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionrundispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::RunDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::RunDispatch {&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a line run.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Motion::RunDispatch::current_stop(self: &amp;amp;amp;Motion::RunDispatch, line: &amp;amp;amp;Line): *Line::Stop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionrunstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::RunStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::RunStop {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its line run.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionstationstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::StationStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::StationStop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Schedule::view(self: &amp;amp;amp;Schedule, shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;): *Shift&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns a pointer to the shift, if it’s contained in this schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-script&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Script ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Script {&lt;br /&gt;
    id: ID&amp;amp;lt;Script&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Shift {&lt;br /&gt;
    id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::kind(self: &amp;amp;amp;Signal): mut SignalKind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the signal kind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Track::max_speed(self: &amp;amp;amp;Track): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the min(physical, manual setting) max speed of the track, in m/s.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
    as_purchased: Train::Dynamics,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-traindynamics&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train::Dynamics ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train::Dynamics {&lt;br /&gt;
    max_speed: f32,&lt;br /&gt;
    max_acceleration: f32,&lt;br /&gt;
    max_regular_braking: f32,&lt;br /&gt;
    max_emergency_braking: f32,&lt;br /&gt;
    max_tractive_effort: f32,&lt;br /&gt;
    total_power: f32,&lt;br /&gt;
    empty_mass: f32,&lt;br /&gt;
    length: f32,&lt;br /&gt;
    max_pax: i32,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vec&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;lt;Motion::CachedHitcher&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Hitch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;): *Motion::Hitch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;): *Motion::RunStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::StationStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt;&lt;br /&gt;
): *Motion::StationStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Script&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Shift&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Shift&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Shift&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciterator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;lt;Motion::CachedHitcher&amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator::next(&lt;br /&gt;
    self: &amp;amp;amp;mut Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator&lt;br /&gt;
): *Motion::CachedHitcher&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    idx: i64&lt;br /&gt;
): *Motion::CachedHitcher&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::clock_us(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current microseconds since the creation of this saved game. This is used as the timing root of the simulation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second since 1970-01-01:00:00:00.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_occupation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_reservation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying or reserving the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_occupying(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_reserving(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying or reserving the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
Probe a track position for train reservations and occupations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::view_last&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Extrapolator, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the last frame Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Seconds since 1970-01-01:00:00:00 for Monday 00:00:00 of the current week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestopevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type LineStopEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum LineStopEvent {&lt;br /&gt;
    Arrive,&lt;br /&gt;
    Depart,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
Advance the iterator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftallow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftAllow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftAllow {&lt;br /&gt;
    Allow,&lt;br /&gt;
    Deny,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftEvent {&lt;br /&gt;
    Assign,&lt;br /&gt;
    Unassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftsetup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftSetup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ShiftSetup {&lt;br /&gt;
    skip: bool,&lt;br /&gt;
    match_pos: bool,&lt;br /&gt;
    check_occupation: bool,&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores the context of a train shift lookup.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function wants to change the train path, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signallookaheadresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalLookaheadResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalLookaheadResult {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores extra information associated with the result of the signal lookahead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-sim&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Sim ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Sim {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of the simulation state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Sim::view&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Sim, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A proxy mutable API to the simulation engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    ev: TaskEventTrain&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_hitch(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    driver: &amp;amp;amp;Train,&lt;br /&gt;
    hitcher: &amp;amp;amp;Train,&lt;br /&gt;
    order: i64,&lt;br /&gt;
    flip: bool&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hitch a train to a driver train. The hitched train is emptied of pax and removed from the sim, while its cars are appended to the driver. The order parameter (from -1000 to 1000) determines the hitched train cars position: the driver train is always order 0, so negative values will put the hitch in front of the driver, and positive values behind it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(self: &amp;amp;amp;mut SimController, train: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_run_line(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    arrival_offset_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_configuration(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    config: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_presence_flip(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    flip: bool&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_stop_delay(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    delay_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add extra delay time to a stopped train that has a timed_stop component.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_unhitch(self: &amp;amp;amp;mut SimController, hitcher: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Remove the hitched state from a train. It will become an unspawned, unassigned train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simplesimcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimpleSimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimpleSimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A limited API version of SimController.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimpleSimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimpleSimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-taskeventtrain&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TaskEventTrain ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum TaskEventTrain {&lt;br /&gt;
    StopArrive,&lt;br /&gt;
    StopDepart,&lt;br /&gt;
    ShiftAssign,&lt;br /&gt;
    ShiftUnassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=564</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=564"/>
		<updated>2026-02-07T17:22:00Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used in game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration, integer division or arbitrary setting of pointers and references, and most data exposed to scripts is read-only, strictly enforced by the language. Any expression result which could result in an out of bounds or invalid memory access must be checked for validity, and the API design together with the type system enforces it.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
pub struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;SpeedTrap,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- VisMod? 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' ColonNAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Script&amp;lt;/code&amp;gt; (with restrictions)&lt;br /&gt;
&lt;br /&gt;
Structs extending game types for player extensions must be declared as &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt;. When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
To read struct objects from script code they must be looked up using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API. Therefore only functions provided with &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt; object (or a context object with contains &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt;) can look up these objects. But you can pass around &amp;lt;code&amp;gt;DB&amp;amp;amp;&amp;lt;/code&amp;gt; as a parameter without any lifetime restrictions, since it’s a purely read only API. This API also works for non-pub structs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= ctx.db.view&amp;amp;lt;Example&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    log(&amp;amp;quot;v = @&amp;amp;quot;, config.v);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;pub-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== pub structs ====&lt;br /&gt;
&lt;br /&gt;
As explained earlier, &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs are the user interface of your scripts. They are exposed in the UI as input forms, and their &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;s can give some control over this rendering. Conceptually they are owned by the player of the game as part of the game object database, by attaching them to a game model object in the database, not the script. Scripts do not have any capability to create, edit or delete objects of &amp;lt;code&amp;gt;pub struct&amp;lt;/code&amp;gt;s. It is always the player who decides when to create a new object of these structs by interacting in the UI. Scripts can then read, and only read, the content of these objects, by using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API presented earlier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs have a very powerful capability: they have limited support for forward schema evolution. This means that the script developer can add to, and reorder, fields in &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, and the game runtime will be able keep the contents of the other fields intact. This is very important to respect the input data by the player. If you rename &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs or their fields, or change their types, the player input data will be lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;non-pub-or-private-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Non-pub (or private) structs ====&lt;br /&gt;
&lt;br /&gt;
Non-&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, also called private structs, are conceptually owned by the script as a part of the simulation, not the player. Their contents are assumed to be a black box by the rest of the game. Scripts are allowed to create and modify objects of these structs during their execution, which are automatically deleted at the end of the simulation frame. It is also possible to attach these structs to existing game model objects to extend their lifetime beyond the current frame. In this case their lifetime becomes the same as the game object, and they can be retrieved in later frames for reading, deleted or overwritten as desired.&lt;br /&gt;
&lt;br /&gt;
Private structs ''do not support schema evolution''. Changing field types, field names, reordering of fields, even just adding new fields at the end, will always result in losing all existing attached objects of the given struct. Some operations like resetting the simulation will also erase attached objects, because they are considered simulation state, not player created objects.&lt;br /&gt;
&lt;br /&gt;
Private structs support dynamic memory allocation. All private struct definitions automatically create a &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; method for the struct:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct PrivData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let ro &amp;amp;amp;= ctx.db.view&amp;amp;lt;PrivData&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    let rw &amp;amp;amp;mut= ro.clone();&lt;br /&gt;
    rw.v = 100;&lt;br /&gt;
    let empty &amp;amp;amp;mut= PrivData::new();&lt;br /&gt;
    empty.v = 200;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The objects allocated by &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; are always deleted at the end of the current simulation frame. Their lifetime can be extended beyond the current frame by attaching them to a game object, like &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, so their lifetime becomes the same as the attached object. The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API has methods for attaching and erasing these object.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;host-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Host structs ====&lt;br /&gt;
&lt;br /&gt;
Many of the exposed game APIs are also based around structs. These structs do not follow any of the previous rules. Some have special capabilities, for example simple structs like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt; are ''value objects'': they can be copied and passed around like any &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; would. Some others are strictly locked down and serve as very little beyond a way to keep a pointer safe. In general, when working with game API structs, assume they are what would be called ''move only'' in C++. And NimbyScript has no move operator or semantics, so in essence assume they are immutable, immobile references, except when documented otherwise (like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As an aside, all script declared &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; or not) are also always ''move only'', and always “owned” by some external entity. This is why the APIs for their manipulation are always based on pointers and references, even for private structs. It is not possible to create plain, stack allocated values of script structs, or to use them as fields in structs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version:&lt;br /&gt;
&lt;br /&gt;
* Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
* Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums)&lt;br /&gt;
* For pub structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* For private structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In pub structs these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types. &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; will also display a small list editor. Keep in mind the correct type is &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;Vec&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types. It will be displayed as the input widget label.&lt;br /&gt;
* The &amp;lt;code&amp;gt;description&amp;lt;/code&amp;gt; meta field is accepted for all field types. It will be displayed as the input widget tooltip.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- 'let' BindBody 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- 'let' BindBody ';'&lt;br /&gt;
BindBody    &amp;amp;lt;- NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' 'let' BindBody BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- ColonNAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere pointer types cannot be dereferenced, therefore cannot be used in dot expressions. The exception is the built-in function &amp;lt;code&amp;gt;is_valid(ptr): bool&amp;lt;/code&amp;gt;, which is usable with any pointer type.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;extensions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Extensions =&lt;br /&gt;
&lt;br /&gt;
Extending game database struct data with &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt; can also be used to extend the game code. The mechanism to do so is to first declare a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;ing a game database object (with or without fields). Then create a specifically named and parametrized function which will be called by the game under certain situations, for certain kinds of objects.&lt;br /&gt;
&lt;br /&gt;
All extension functions take a &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter which is a reference to the struct which it is method of, called &amp;lt;code&amp;gt;Example&amp;lt;/code&amp;gt; in the following sections. Replace it with your struct name. The rest of the parameters are fixed and must be reproduced exactly as-is.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
Event functions are called as part of the core simulation engine. They are meant to be focused in features and quick to execute. These functions might be called thousands of times per simulation frame, including multiple redundant times. Their capability to change the simulation behavior is usually very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_check&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_check ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails, or if another script call returns &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_lookahead&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_lookahead ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_lookahead(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    train_distance: f64,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalLookaheadResult&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; function at regular intervals for each signal 15km ahead of the train path. It is called for all signals, until one of these conditions hold:&lt;br /&gt;
&lt;br /&gt;
* One of the signals path checks as &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;&lt;br /&gt;
* Another train is found&lt;br /&gt;
* The train stop is found&lt;br /&gt;
* 15km have been checked&lt;br /&gt;
&lt;br /&gt;
For both &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; signals, your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; will be called, and you can check the path find result in &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;, and the distance from the train in &amp;lt;code&amp;gt;train_distance&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; allows to set a maximum speed for the train, which goes into effect immediately. It must be expressed as m/s. This works from any distance and past any amount of signals between the train and the caller signal. If multiple signals in the lookahead path return a &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt;, the slowest speed is picked. If no &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt; is set, or it is 0, the result is ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; default value is 0, which is considered invalid and will be ignored. To stop the train at the signal implement &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_change_path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_change_path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_change_path(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The current path check result of this signal for the passed train is passed as &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;. This already includes any results from &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_pass_by&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_pass_by ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_pass_by(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; function on the exact simulation frame a train passes by the exact point of the signal on the track.&lt;br /&gt;
&lt;br /&gt;
This function has no return result. Instead, since it has a predictably low call rate compared to the other events, it is the only event function with access to the powerful &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_marker_reserved&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_marker_reserved ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given marker signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; any time the reservation check algorithm is tracing a path which goes over the marker signal, on any direction, giving it the chance to report an arbitrary train as the reserver of that point on the track.&lt;br /&gt;
&lt;br /&gt;
This signal has a potential huge call rate, and for this reason it is given very little access to the APIs. The intention is that all the state required by this signal is calculated somewhere else and attached to the signal as a private struct object, or to some object reachable from it. Don’t worry about filtering for the “same train” cases, this is automatically done.&lt;br /&gt;
&lt;br /&gt;
If no reservation is desired, use the &amp;lt;code&amp;gt;empty&amp;lt;/code&amp;gt; global method available in all &amp;lt;code&amp;gt;ID&amp;amp;lt;Class&amp;amp;gt;&amp;lt;/code&amp;gt; types: &amp;lt;code&amp;gt;return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {}&lt;br /&gt;
struct Owner {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; {&lt;br /&gt;
    // some other, more full featured script function has attached Owner to this signal,&lt;br /&gt;
    // or not, so we need to check first&lt;br /&gt;
    if let owner &amp;amp;amp;= db.view&amp;amp;lt;Owner&amp;amp;gt;(signal) {&lt;br /&gt;
        if is_valid(db.view(owner.train_id)) {&lt;br /&gt;
            return owner.train_id;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_texture_state&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_texture_state ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_texture_state(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    clock_us: i64,&lt;br /&gt;
    core_state: i64&lt;br /&gt;
): i64 { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment, when the game UI needs to query what is the current signal texture state index, it will call your &amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt;, with some potential caching to keep the call rate lower. In any case the call rate of this function is potentially very large when the user zooms out the map, so make sure to keep its code as efficient as possible. For this same reason it is given very little access to the APIs. &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; is the number of sim-microseconds since the current save was created, you can use it with the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; functions to make animations. For path signals, &amp;lt;code&amp;gt;core_state&amp;lt;/code&amp;gt; returns the current result of the signal check (including scripts), and it is valued 0 for Pass and 1 for Stop; for all other signals it is always 0.&lt;br /&gt;
&lt;br /&gt;
The return value indicates which signal texture state is to be used. If it’s -1 or lower, the default algorithm will be used to select the texture index. If it’s 0 or larger, it will select the texture in the same order as the &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; lines in the &amp;lt;code&amp;gt;SignalTextures&amp;lt;/code&amp;gt;. Larger values than the number of states will be clamped to the last state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_setup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_setup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_setup(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ss: &amp;amp;amp;mut ShiftSetup&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when an unassigned train decides to lookup a new shift to run, it will first call &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The parameter &amp;lt;code&amp;gt;ss&amp;lt;/code&amp;gt; is both an input and output parameter. It is initialized with the current, relevant data for the given train state, and &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; can then change it, to influence which shifts will be considered by the shift selection algorithm. It can change the train position used for matching, the time used for matching, and disable the check for reservations. For matched shifts which do not correspond to the current train position, the Extrapolator system will automatically pathfind a temporary milestone for the train, like other path-changing features. &amp;lt;code&amp;gt;ShiftSetup::epoch_s&amp;lt;/code&amp;gt; allowed range is between minus one week and plus one week from the current simulation time, with values outside this range being clamped into it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_allow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_allow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_allow(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    run: &amp;amp;amp;Run,&lt;br /&gt;
    stop_idx: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    pose: &amp;amp;amp;Pose&lt;br /&gt;
): ShiftAllow { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when the shift selection algorithm fins a valid shift for the given train, it will call &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; with all the relevant data. The return of the function can then allow or deny the shift. If the shift is denied, the algorithm will resume immediately, trying other shifts&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are independent from each other, and can be used in any combination.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;linestop-event_line_stop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Line::Stop event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestStop extend Line::Stop {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestStop::event_line_stop(&lt;br /&gt;
    self: &amp;amp;amp;TestStop,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == LineStopEvent::Arrive {&lt;br /&gt;
        log(&amp;amp;quot;@ arrives @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ departs @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given line stop in the line editor. From that moment, when any train arrives or departs said line stop, &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LineStopEvent::Depart&amp;lt;/code&amp;gt; to distinguish between arrival and departure. Waypoints are only called for &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt;. Shift-less trains are also called.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;shift-event_shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Shift event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestShift extend Shift {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestShift::event_shift(&lt;br /&gt;
    self: &amp;amp;amp;TestShift,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == ShiftEvent::Assign {&lt;br /&gt;
        log(&amp;amp;quot;@ assigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ unassigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given schedule shift in the line editor. From that moment, when any train is assigned to the shift, or becomes unassigned from the shift, &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;ShiftEvent::Assign&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ShiftEvent::Unassign&amp;lt;/code&amp;gt; to distinguish between assignation and unassignation. The &amp;lt;code&amp;gt;Assign&amp;lt;/code&amp;gt; event is called just after &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been set up, so it already has all the shift and run information. The &amp;lt;code&amp;gt;Unassign&amp;lt;/code&amp;gt; event is called just before &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been cleared of all shift and run information so the script has access to as much information as possible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;global-events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Global events ==&lt;br /&gt;
&lt;br /&gt;
Like event functions of struct extensions, global events are called as part of the core simulation engine when a specific event occurs, but they are not associated to any struct. Instead they are public top level functions with the signature given in this document. Global event functions are always called if they exist in a script and the event occurs.&lt;br /&gt;
&lt;br /&gt;
=== global_event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn global_event_line_stop(&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    log(&amp;amp;quot;global_event_line_stop: @ on line @&amp;amp;quot;, train, line);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Arguments and conditions are identical to &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt;, except there is no &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter.&lt;br /&gt;
&lt;br /&gt;
=== global_event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn global_event_shift(&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    log(&amp;amp;quot;global_event_shift: @ on sched @&amp;amp;quot;, train, sched);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Arguments and conditions are identical to &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt;, except there is no &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;controllers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Controllers ==&lt;br /&gt;
&lt;br /&gt;
Controller functions are called at a low frame rate compared to the overall simulation, with an (unchangeable) rate of once in 6 sim-seconds. They do not need any specific event or trigger to run, other than their enforced timer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-control_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train control_train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct HateDepots extend Train {}&lt;br /&gt;
pub fn HateDepots::control_train(&lt;br /&gt;
    self: &amp;amp;amp;HateDepots,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    // train is already removed from the tracks, don't interfere with potential attempts at shift assignation&lt;br /&gt;
    if !is_valid(motion.presence.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is running a schedule, don't interfere&lt;br /&gt;
    if is_valid(motion.schedule_dispatch.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is present, but it is not running a schedule, so despawn it&lt;br /&gt;
    sc.queue_train_intervention(train);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The train motion engine will call train controllers in the multithreaded phase, as part of the regular train motion extrapolator, after all the C++ code is done for a frame for a particular train, but before any queued commands are executed. Command execution will only happen after all train controllers for a given frame are done. In other words, train controllers queue up work to be executed by the sim. They never directly change the sim in any way, allowing train controller execution to be fully parallel.&lt;br /&gt;
&lt;br /&gt;
After all controllers are run, and all their non-task commands are executed, and then tasks are executed. Read more about tasks later on. Any tasks with a deadline which expired in this frame a run at this time too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontroller-command-queue&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== SimController command queue ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; object implements an API to control the simulation, including modification of some parameters and behaviors. It is also responsible for attaching and erasing private struct data from game objects, on behalf of scripts. The execution of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; is based on a command queue. Every call queues a command and returns immediately to the script code, without making any changes to the game state. Therefore the game state never changes while the script code is running.&lt;br /&gt;
&lt;br /&gt;
Commands queued from events and &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt; are executed asynchronously, there is no guaranteed order of execution! You must prepare your code and data for this design. For stand alone tasks scripts commands are executed in order and in isolation. You can queue up tasks from event and control scripts when you need to guarantee data consistency beyond “pick a random winner”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SimpleSimController&amp;lt;/code&amp;gt; is a cut down version of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; for high frequency events like &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt;. The reference in the second part of this document lists which &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; functions are available in &amp;lt;code&amp;gt;SimpleSimController&amp;lt;/code&amp;gt;, and they work identically.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_intervention&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_intervention ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks, releases its schedule shift (if any), and deletes and refunds its pax (if any). No other cost other than pax refunds is issued. This function can be used as a general “despawn the train” feature, not just for exceptional circumstances.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_warp&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_warp ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks and repositions it at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, re-pathing it to its currently scheduled destination (if any), and setting its speed to 0. This is basically a train wormhole. The train keeps its shift and pax, if any.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_drive_to&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_drive_to ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Re-paths the train path to end at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, without any changes to its shift or pax (if any). It is possible for any future &amp;lt;code&amp;gt;queue_train_drive_to&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; to reset this path at any point, losing the destination. “Queue” here is used as part of the SimController API semantics, it does not mean the train keeps a queue of positions to reach. If the path is not interrupted and the train reaches &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; it will re-path itself towards its current scheduled stop, if it has any, or brake to a stop if unassigned. If &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; was also in the stop area set for its current scheduled stop it will also brake to stop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_attach&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_attach ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the attachment of the &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;existing.clone()&amp;lt;/code&amp;gt;) to the &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt;, which must be of one of the following types: &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attached objects can be accessed with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt; at some point in the future. If called from a controller function, the attached object will be accessible after all controller functions are done for a given frame. If called from a task, he attached object will be accessible immediately after the task returns, and before any other task is executed. In other words, tasks are transaction-like, in the sense they view an immutable snapshot of the game state, and any changes they queue are executed before any other task, and then visible from these other tasks.&lt;br /&gt;
&lt;br /&gt;
Attaching an object of a given private struct type when it already exists attached to a &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt; will overwrite it. This is how private data is updated from scripting: by using &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; to copy any existing data, modifying the copy, then calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; to replace the existing data. Therefore it is a good idea to keep your private structs small. Only one instance of a given private struct type can be attached to any particular model object, but you can attach as many different private struct types as you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_erase&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_erase ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the erasure of &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt;, which must obtained using with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt;. Trying to erase temporary objects (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;existing.clone()&amp;lt;/code&amp;gt;) is ignored. The execution of the queued erase commands is analog to the &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; case. In particular a sequences of attach and erase queued from controllers will produce undefined results (impossible to predict which attach and/or erase wins). For example multiple attach from a controller for the same model_obj and private struct type will implicitly pick a singular “winner” attach, but the script does not have any control over which one. Sequences of attach and erase queued from tasks are strictly ordered and isolated, so they produce consistent results, in the same order they were queued in the task script, without any concurrent changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task-and-simcontrollerqueue_task_at&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task and SimController::queue_task_at ===&lt;br /&gt;
&lt;br /&gt;
See [[#Control%20tasks|control tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task_event_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task_event_train ===&lt;br /&gt;
&lt;br /&gt;
See [[#Event%20tasks|event tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;control-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Control tasks ==&lt;br /&gt;
&lt;br /&gt;
Control tasks are a very special kind of command which allows scripts to dynamically queue “future work”, with privileged access to the sim. Scripts with access to &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; can call this function to queue up a task for future script execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; must be of a private struct type which implements &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example { ... }&lt;br /&gt;
pub fn Example::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
For example, a train controller script could decide it needs to delay some decision into a task for data consistency reasons (other controllers are running at the same time), and delegate into a task rather than directly calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ControlTrain extend Train { ... }&lt;br /&gt;
pub fn ControlTrain::control_train(&lt;br /&gt;
    self: &amp;amp;amp;ControlTrain,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    task.train_id = train.id;&lt;br /&gt;
    task.v = some_data_from_somewhere;&lt;br /&gt;
    task.prio = 42; // or something smarter, like from ControlTrain, other objects, etc.&lt;br /&gt;
    sc.queue_task(task);&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
struct Task {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
struct SomeData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
pub fn Task::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    let train &amp;amp;amp;= ctx.db.view(self.train_id) else { return; }&lt;br /&gt;
    if let existing &amp;amp;amp;= ctx.db.view&amp;amp;lt;SomeData&amp;amp;gt;(train) {&lt;br /&gt;
        if existing.prio &amp;amp;gt;= self.prio {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    let data = SomeData::new();&lt;br /&gt;
    data.v = self.v;&lt;br /&gt;
    data.prio = self.prio;&lt;br /&gt;
    sc.queue_attach(train, data);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the previous example, maybe &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; will be called multiple times because multiple &amp;lt;code&amp;gt;ControlTrain::control_train()&amp;lt;/code&amp;gt; instances queued objects of &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;, but each execution will be single threaded, and all its queued &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; commands will be executed just after the call is done and before any other &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; call (for &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; or any other struct type), therefore the algorithm to pick a winner based on an explicit priority works.&lt;br /&gt;
&lt;br /&gt;
As mentioned, task execution is single threaded. The game does not feature a real concurrent database, instead all concurrent access is bespoke and very carefully designed to avoid deadlocks and inconsistencies (this is much faster than a general purpose concurrent database). Scripts also run in this parallel system, but their access to the game state is carefully restricted as explained earlier. But in the end, scripts also need to modify data, and do so in a consistent way. Tasks solve this issue, but do so in the most pessimistic possible way, by being single threaded. Therefore script developers should use them in moderation. Consider the “random winner” semantics of control script queuing first, which are completely free performance wise, before deciding you need a task. It is often the case a concurrent problem reduces to “pick 0 or 1 winners, any winner, but never 2 or more” and the default queue semantics already provide that guarantee for attaching a specific model/private pair.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; is provided with &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt;, therefore it can queue tasks itself. But unlike controller queuing tasks, which are guaranteed to run on the same frame, tasks queued from tasks are guaranteed to ''not'' run on the same frame, on purpose. They are deliberately stored away and forced a delay of 6 sim-seconds. This is to avoid misuse of tasks, and infinite looping.&lt;br /&gt;
&lt;br /&gt;
This behavior might even be desirable in certain scripts, for example if you are developing some stateful signal system and you need some kind of “cleanup” task that makes sure some signal being owned by some train is still the focus of said train. You can deliberately queue tasks for future simulation frames with &amp;lt;code&amp;gt;queue_task_at&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;deadline&amp;lt;/code&amp;gt; is expressed as microseconds since the start of the current save world. You can obtain the current simulation frame &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; value with &amp;lt;code&amp;gt;Extrapolator::clock_us()&amp;lt;/code&amp;gt;, like in this example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;    // schedule task to run 10 sim-s from now&lt;br /&gt;
    sc.queue_task_at(task, ctx.extrapolator.clock_us() + 10000000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;event-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Event tasks ==&lt;br /&gt;
&lt;br /&gt;
Event tasks are a lightweight version of tasks which run when triggered by certain events. Unlike control tasks, event tasks do not have unlimited access to the sim. Instead the run under an &amp;lt;code&amp;gt;EventCtx&amp;lt;/code&amp;gt; like pub struct events, and run multithreaded, at the same time as the C++ code. Unlike the regular &amp;lt;code&amp;gt;event_*&amp;lt;/code&amp;gt; methods, event tasks are queued for execution by script code, not by UI player commands. The design idea of these tasks is to offer a more focused and efficient execution model than &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt;: they are executed immediately once the relevant event happens, in multithreaded context, rather than require passive polling which might even miss certain events and force execution of single thread code.&lt;br /&gt;
&lt;br /&gt;
Any function with a &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; parameter can queue an even task like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Task {...}&lt;br /&gt;
fn f(..., train: &amp;amp;amp;Train, sc: &amp;amp;amp;mut SimController) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    sc.queue_task_event_train(task, train, TaskEventTrain::StopDepart);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
On the next stop departure of the train the &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt; method will be called:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn Task::task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: TaskEventTrain,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == TaskEventTrain::StopDepart {&lt;br /&gt;
        log(&amp;amp;quot;@ departs&amp;amp;quot;, train);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Like control tasks, event tasks encapsulate a single call. If a series of calls are desired, the task can requeue itself by calling &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt;. Event tasks are limited to a maximum of 1 for every possible train-struct-event combination, to avoid leaks. Trying to queue again the same train-struct-event combination will overwrite any existing task. Only the train and motion are provided as parameters. The code can then drill into motion to extract any required information, like shift or line.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-controlctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ControlCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ControlCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    sim: &amp;amp;amp;Sim,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim controller scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects, and associated script stuct objects.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::track_pos_project(self: &amp;amp;amp;DB, pos: &amp;amp;amp;Pos, distance: f64): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return a track position separated by ‘distance’ meters from ‘pos’, in the direction of ‘pos’. If distance is negative it will be in the opposite direction. Can only follow the main track. Merges and dead ends will return a Pos a shorter distance away. Signals are ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view_self(self: &amp;amp;amp;DB): &amp;amp;amp;Script&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-eventctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type EventCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct EventCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim event handler scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line::Stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line::Stop {&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    cars_config: i32,&lt;br /&gt;
    dynamics: Train::Dynamics,&lt;br /&gt;
    hitched_by: Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    station_stop: std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt;,&lt;br /&gt;
    run_stop: std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
    run_dispatch: std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;,&lt;br /&gt;
    hitch: std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motioncachedhitcher&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::CachedHitcher ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::CachedHitcher {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionhitch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Hitch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Hitch {&lt;br /&gt;
    driver_train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    flip: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Train is being hitched by a driver train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
    flip: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionrundispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::RunDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::RunDispatch {&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a line run.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Motion::RunDispatch::current_stop(self: &amp;amp;amp;Motion::RunDispatch, line: &amp;amp;amp;Line): *Line::Stop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionrunstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::RunStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::RunStop {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its line run.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionstationstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::StationStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::StationStop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Schedule::view(self: &amp;amp;amp;Schedule, shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;): *Shift&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns a pointer to the shift, if it’s contained in this schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-script&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Script ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Script {&lt;br /&gt;
    id: ID&amp;amp;lt;Script&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Shift {&lt;br /&gt;
    id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::kind(self: &amp;amp;amp;Signal): mut SignalKind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the signal kind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Track::max_speed(self: &amp;amp;amp;Track): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the min(physical, manual setting) max speed of the track, in m/s.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
    as_purchased: Train::Dynamics,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-traindynamics&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train::Dynamics ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train::Dynamics {&lt;br /&gt;
    max_speed: f32,&lt;br /&gt;
    max_acceleration: f32,&lt;br /&gt;
    max_regular_braking: f32,&lt;br /&gt;
    max_emergency_braking: f32,&lt;br /&gt;
    max_tractive_effort: f32,&lt;br /&gt;
    total_power: f32,&lt;br /&gt;
    empty_mass: f32,&lt;br /&gt;
    length: f32,&lt;br /&gt;
    max_pax: i32,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vec&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;lt;Motion::CachedHitcher&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Hitch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;): *Motion::Hitch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;): *Motion::RunStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::StationStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt;&lt;br /&gt;
): *Motion::StationStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Script&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Shift&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Shift&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Shift&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciterator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;lt;Motion::CachedHitcher&amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator::next(&lt;br /&gt;
    self: &amp;amp;amp;mut Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator&lt;br /&gt;
): *Motion::CachedHitcher&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    idx: i64&lt;br /&gt;
): *Motion::CachedHitcher&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::clock_us(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current microseconds since the creation of this saved game. This is used as the timing root of the simulation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second since 1970-01-01:00:00:00.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_occupation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_reservation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying or reserving the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_occupying(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_reserving(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying or reserving the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
Probe a track position for train reservations and occupations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::view_last&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Extrapolator, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the last frame Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Seconds since 1970-01-01:00:00:00 for Monday 00:00:00 of the current week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestopevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type LineStopEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum LineStopEvent {&lt;br /&gt;
    Arrive,&lt;br /&gt;
    Depart,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
Advance the iterator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftallow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftAllow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftAllow {&lt;br /&gt;
    Allow,&lt;br /&gt;
    Deny,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftEvent {&lt;br /&gt;
    Assign,&lt;br /&gt;
    Unassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftsetup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftSetup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ShiftSetup {&lt;br /&gt;
    skip: bool,&lt;br /&gt;
    match_pos: bool,&lt;br /&gt;
    check_occupation: bool,&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores the context of a train shift lookup.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function wants to change the train path, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signallookaheadresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalLookaheadResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalLookaheadResult {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores extra information associated with the result of the signal lookahead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-sim&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Sim ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Sim {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of the simulation state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Sim::view&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Sim, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A proxy mutable API to the simulation engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    ev: TaskEventTrain&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_hitch(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    driver: &amp;amp;amp;Train,&lt;br /&gt;
    hitcher: &amp;amp;amp;Train,&lt;br /&gt;
    order: i64,&lt;br /&gt;
    flip: bool&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hitch a train to a driver train. The hitched train is emptied of pax and removed from the sim, while its cars are appended to the driver. The order parameter (from -1000 to 1000) determines the hitched train cars position: the driver train is always order 0, so negative values will put the hitch in front of the driver, and positive values behind it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(self: &amp;amp;amp;mut SimController, train: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_run_line(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    arrival_offset_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_configuration(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    config: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_presence_flip(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    flip: bool&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_stop_delay(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    delay_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add extra delay time to a stopped train that has a timed_stop component.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_unhitch(self: &amp;amp;amp;mut SimController, hitcher: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Remove the hitched state from a train. It will become an unspawned, unassigned train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simplesimcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimpleSimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimpleSimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A limited API version of SimController.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimpleSimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimpleSimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-taskeventtrain&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TaskEventTrain ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum TaskEventTrain {&lt;br /&gt;
    StopArrive,&lt;br /&gt;
    StopDepart,&lt;br /&gt;
    ShiftAssign,&lt;br /&gt;
    ShiftUnassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=563</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=563"/>
		<updated>2026-02-06T18:05:43Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used in game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration, integer division or arbitrary setting of pointers and references, and most data exposed to scripts is read-only, strictly enforced by the language. Any expression result which could result in an out of bounds or invalid memory access must be checked for validity, and the API design together with the type system enforces it.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
pub struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;SpeedTrap,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- VisMod? 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' ColonNAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Script&amp;lt;/code&amp;gt; (with restrictions)&lt;br /&gt;
&lt;br /&gt;
Structs extending game types for player extensions must be declared as &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt;. When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
To read struct objects from script code they must be looked up using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API. Therefore only functions provided with &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt; object (or a context object with contains &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt;) can look up these objects. But you can pass around &amp;lt;code&amp;gt;DB&amp;amp;amp;&amp;lt;/code&amp;gt; as a parameter without any lifetime restrictions, since it’s a purely read only API. This API also works for non-pub structs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= ctx.db.view&amp;amp;lt;Example&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    log(&amp;amp;quot;v = @&amp;amp;quot;, config.v);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;pub-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== pub structs ====&lt;br /&gt;
&lt;br /&gt;
As explained earlier, &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs are the user interface of your scripts. They are exposed in the UI as input forms, and their &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;s can give some control over this rendering. Conceptually they are owned by the player of the game as part of the game object database, by attaching them to a game model object in the database, not the script. Scripts do not have any capability to create, edit or delete objects of &amp;lt;code&amp;gt;pub struct&amp;lt;/code&amp;gt;s. It is always the player who decides when to create a new object of these structs by interacting in the UI. Scripts can then read, and only read, the content of these objects, by using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API presented earlier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs have a very powerful capability: they have limited support for forward schema evolution. This means that the script developer can add to, and reorder, fields in &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, and the game runtime will be able keep the contents of the other fields intact. This is very important to respect the input data by the player. If you rename &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs or their fields, or change their types, the player input data will be lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;non-pub-or-private-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Non-pub (or private) structs ====&lt;br /&gt;
&lt;br /&gt;
Non-&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, also called private structs, are conceptually owned by the script as a part of the simulation, not the player. Their contents are assumed to be a black box by the rest of the game. Scripts are allowed to create and modify objects of these structs during their execution, which are automatically deleted at the end of the simulation frame. It is also possible to attach these structs to existing game model objects to extend their lifetime beyond the current frame. In this case their lifetime becomes the same as the game object, and they can be retrieved in later frames for reading, deleted or overwritten as desired.&lt;br /&gt;
&lt;br /&gt;
Private structs ''do not support schema evolution''. Changing field types, field names, reordering of fields, even just adding new fields at the end, will always result in losing all existing attached objects of the given struct. Some operations like resetting the simulation will also erase attached objects, because they are considered simulation state, not player created objects.&lt;br /&gt;
&lt;br /&gt;
Private structs support dynamic memory allocation. All private struct definitions automatically create a &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; method for the struct:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct PrivData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let ro &amp;amp;amp;= ctx.db.view&amp;amp;lt;PrivData&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    let rw &amp;amp;amp;mut= ro.clone();&lt;br /&gt;
    rw.v = 100;&lt;br /&gt;
    let empty &amp;amp;amp;mut= PrivData::new();&lt;br /&gt;
    empty.v = 200;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The objects allocated by &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; are always deleted at the end of the current simulation frame. Their lifetime can be extended beyond the current frame by attaching them to a game object, like &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, so their lifetime becomes the same as the attached object. The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API has methods for attaching and erasing these object.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;host-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Host structs ====&lt;br /&gt;
&lt;br /&gt;
Many of the exposed game APIs are also based around structs. These structs do not follow any of the previous rules. Some have special capabilities, for example simple structs like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt; are ''value objects'': they can be copied and passed around like any &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; would. Some others are strictly locked down and serve as very little beyond a way to keep a pointer safe. In general, when working with game API structs, assume they are what would be called ''move only'' in C++. And NimbyScript has no move operator or semantics, so in essence assume they are immutable, immobile references, except when documented otherwise (like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As an aside, all script declared &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; or not) are also always ''move only'', and always “owned” by some external entity. This is why the APIs for their manipulation are always based on pointers and references, even for private structs. It is not possible to create plain, stack allocated values of script structs, or to use them as fields in structs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version:&lt;br /&gt;
&lt;br /&gt;
* Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
* Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums)&lt;br /&gt;
* For pub structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* For private structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In pub structs these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types. &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; will also display a small list editor. Keep in mind the correct type is &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;Vec&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types. It will be displayed as the input widget label.&lt;br /&gt;
* The &amp;lt;code&amp;gt;description&amp;lt;/code&amp;gt; meta field is accepted for all field types. It will be displayed as the input widget tooltip.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- 'let' BindBody 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- 'let' BindBody ';'&lt;br /&gt;
BindBody    &amp;amp;lt;- NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' 'let' BindBody BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- ColonNAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere pointer types cannot be dereferenced, therefore cannot be used in dot expressions. The exception is the built-in function &amp;lt;code&amp;gt;is_valid(ptr): bool&amp;lt;/code&amp;gt;, which is usable with any pointer type.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;extensions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Extensions =&lt;br /&gt;
&lt;br /&gt;
Extending game database struct data with &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt; can also be used to extend the game code. The mechanism to do so is to first declare a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;ing a game database object (with or without fields). Then create a specifically named and parametrized function which will be called by the game under certain situations, for certain kinds of objects.&lt;br /&gt;
&lt;br /&gt;
All extension functions take a &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter which is a reference to the struct which it is method of, called &amp;lt;code&amp;gt;Example&amp;lt;/code&amp;gt; in the following sections. Replace it with your struct name. The rest of the parameters are fixed and must be reproduced exactly as-is.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
Event functions are called as part of the core simulation engine. They are meant to be focused in features and quick to execute. These functions might be called thousands of times per simulation frame, including multiple redundant times. Their capability to change the simulation behavior is usually very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_check&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_check ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails, or if another script call returns &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_lookahead&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_lookahead ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_lookahead(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    train_distance: f64,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalLookaheadResult&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; function at regular intervals for each signal 15km ahead of the train path. It is called for all signals, until one of these conditions hold:&lt;br /&gt;
&lt;br /&gt;
* One of the signals path checks as &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;&lt;br /&gt;
* Another train is found&lt;br /&gt;
* The train stop is found&lt;br /&gt;
* 15km have been checked&lt;br /&gt;
&lt;br /&gt;
For both &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; signals, your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; will be called, and you can check the path find result in &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;, and the distance from the train in &amp;lt;code&amp;gt;train_distance&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; allows to set a maximum speed for the train, which goes into effect immediately. It must be expressed as m/s. This works from any distance and past any amount of signals between the train and the caller signal. If multiple signals in the lookahead path return a &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt;, the slowest speed is picked. If no &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt; is set, or it is 0, the result is ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; default value is 0, which is considered invalid and will be ignored. To stop the train at the signal implement &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_change_path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_change_path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_change_path(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The current path check result of this signal for the passed train is passed as &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;. This already includes any results from &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_pass_by&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_pass_by ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_pass_by(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; function on the exact simulation frame a train passes by the exact point of the signal on the track.&lt;br /&gt;
&lt;br /&gt;
This function has no return result. Instead, since it has a predictably low call rate compared to the other events, it is the only event function with access to the powerful &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_marker_reserved&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_marker_reserved ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given marker signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; any time the reservation check algorithm is tracing a path which goes over the marker signal, on any direction, giving it the chance to report an arbitrary train as the reserver of that point on the track.&lt;br /&gt;
&lt;br /&gt;
This signal has a potential huge call rate, and for this reason it is given very little access to the APIs. The intention is that all the state required by this signal is calculated somewhere else and attached to the signal as a private struct object, or to some object reachable from it. Don’t worry about filtering for the “same train” cases, this is automatically done.&lt;br /&gt;
&lt;br /&gt;
If no reservation is desired, use the &amp;lt;code&amp;gt;empty&amp;lt;/code&amp;gt; global method available in all &amp;lt;code&amp;gt;ID&amp;amp;lt;Class&amp;amp;gt;&amp;lt;/code&amp;gt; types: &amp;lt;code&amp;gt;return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {}&lt;br /&gt;
struct Owner {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; {&lt;br /&gt;
    // some other, more full featured script function has attached Owner to this signal,&lt;br /&gt;
    // or not, so we need to check first&lt;br /&gt;
    if let owner &amp;amp;amp;= db.view&amp;amp;lt;Owner&amp;amp;gt;(signal) {&lt;br /&gt;
        if is_valid(db.view(owner.train_id)) {&lt;br /&gt;
            return owner.train_id;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_texture_state&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_texture_state ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_texture_state(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    clock_us: i64&lt;br /&gt;
): i64 { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment, when the game UI needs to query what is the current signal texture state index, it will call your &amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt;, with some potential caching to keep the call rate lower. In any case the call rate of this function is potentially very large when the user zooms out the map, so make sure to keep its code as efficient as possible. For this same reason it is given very little access to the APIs. &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; is the number of sim-microseconds since the current save was created, you use it with the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; functions to make animations.&lt;br /&gt;
&lt;br /&gt;
The return value indicates which signal texture state is to be used. If it’s -1 or lower, the default algorithm will be used to select the texture index. If it’s 0 or larger, it will select the texture in the same order as the &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; lines in the &amp;lt;code&amp;gt;SignalTextures&amp;lt;/code&amp;gt;. Larger values than the number of states will be clamped to the last state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_setup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_setup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_setup(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ss: &amp;amp;amp;mut ShiftSetup&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when an unassigned train decides to lookup a new shift to run, it will first call &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The parameter &amp;lt;code&amp;gt;ss&amp;lt;/code&amp;gt; is both an input and output parameter. It is initialized with the current, relevant data for the given train state, and &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; can then change it, to influence which shifts will be considered by the shift selection algorithm. It can change the train position used for matching, the time used for matching, and disable the check for reservations. For matched shifts which do not correspond to the current train position, the Extrapolator system will automatically pathfind a temporary milestone for the train, like other path-changing features. &amp;lt;code&amp;gt;ShiftSetup::epoch_s&amp;lt;/code&amp;gt; allowed range is between minus one week and plus one week from the current simulation time, with values outside this range being clamped into it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_allow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_allow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_allow(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    run: &amp;amp;amp;Run,&lt;br /&gt;
    stop_idx: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    pose: &amp;amp;amp;Pose&lt;br /&gt;
): ShiftAllow { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when the shift selection algorithm fins a valid shift for the given train, it will call &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; with all the relevant data. The return of the function can then allow or deny the shift. If the shift is denied, the algorithm will resume immediately, trying other shifts&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are independent from each other, and can be used in any combination.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;linestop-event_line_stop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Line::Stop event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestStop extend Line::Stop {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestStop::event_line_stop(&lt;br /&gt;
    self: &amp;amp;amp;TestStop,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == LineStopEvent::Arrive {&lt;br /&gt;
        log(&amp;amp;quot;@ arrives @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ departs @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given line stop in the line editor. From that moment, when any train arrives or departs said line stop, &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LineStopEvent::Depart&amp;lt;/code&amp;gt; to distinguish between arrival and departure. Waypoints are only called for &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt;. Shift-less trains are also called.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;shift-event_shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Shift event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestShift extend Shift {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestShift::event_shift(&lt;br /&gt;
    self: &amp;amp;amp;TestShift,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == ShiftEvent::Assign {&lt;br /&gt;
        log(&amp;amp;quot;@ assigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ unassigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given schedule shift in the line editor. From that moment, when any train is assigned to the shift, or becomes unassigned from the shift, &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;ShiftEvent::Assign&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ShiftEvent::Unassign&amp;lt;/code&amp;gt; to distinguish between assignation and unassignation. The &amp;lt;code&amp;gt;Assign&amp;lt;/code&amp;gt; event is called just after &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been set up, so it already has all the shift and run information. The &amp;lt;code&amp;gt;Unassign&amp;lt;/code&amp;gt; event is called just before &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been cleared of all shift and run information so the script has access to as much information as possible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;global-events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Global events ==&lt;br /&gt;
&lt;br /&gt;
Like event functions of struct extensions, global events are called as part of the core simulation engine when a specific event occurs, but they are not associated to any struct. Instead they are public top level functions with the signature given in this document. Global event functions are always called if they exist in a script and the event occurs.&lt;br /&gt;
&lt;br /&gt;
=== global_event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn global_event_line_stop(&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    log(&amp;amp;quot;global_event_line_stop: @ on line @&amp;amp;quot;, train, line);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Arguments and conditions are identical to &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt;, except there is no &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter.&lt;br /&gt;
&lt;br /&gt;
=== global_event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn global_event_shift(&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    log(&amp;amp;quot;global_event_shift: @ on sched @&amp;amp;quot;, train, sched);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Arguments and conditions are identical to &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt;, except there is no &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;controllers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Controllers ==&lt;br /&gt;
&lt;br /&gt;
Controller functions are called at a low frame rate compared to the overall simulation, with an (unchangeable) rate of once in 6 sim-seconds. They do not need any specific event or trigger to run, other than their enforced timer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-control_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train control_train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct HateDepots extend Train {}&lt;br /&gt;
pub fn HateDepots::control_train(&lt;br /&gt;
    self: &amp;amp;amp;HateDepots,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    // train is already removed from the tracks, don't interfere with potential attempts at shift assignation&lt;br /&gt;
    if !is_valid(motion.presence.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is running a schedule, don't interfere&lt;br /&gt;
    if is_valid(motion.schedule_dispatch.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is present, but it is not running a schedule, so despawn it&lt;br /&gt;
    sc.queue_train_intervention(train);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The train motion engine will call train controllers in the multithreaded phase, as part of the regular train motion extrapolator, after all the C++ code is done for a frame for a particular train, but before any queued commands are executed. Command execution will only happen after all train controllers for a given frame are done. In other words, train controllers queue up work to be executed by the sim. They never directly change the sim in any way, allowing train controller execution to be fully parallel.&lt;br /&gt;
&lt;br /&gt;
After all controllers are run, and all their non-task commands are executed, and then tasks are executed. Read more about tasks later on. Any tasks with a deadline which expired in this frame a run at this time too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontroller-command-queue&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== SimController command queue ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; object implements an API to control the simulation, including modification of some parameters and behaviors. It is also responsible for attaching and erasing private struct data from game objects, on behalf of scripts. The execution of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; is based on a command queue. Every call queues a command and returns immediately to the script code, without making any changes to the game state. Therefore the game state never changes while the script code is running.&lt;br /&gt;
&lt;br /&gt;
Commands queued from events and &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt; are executed asynchronously, there is no guaranteed order of execution! You must prepare your code and data for this design. For stand alone tasks scripts commands are executed in order and in isolation. You can queue up tasks from event and control scripts when you need to guarantee data consistency beyond “pick a random winner”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SimpleSimController&amp;lt;/code&amp;gt; is a cut down version of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; for high frequency events like &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt;. The reference in the second part of this document lists which &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; functions are available in &amp;lt;code&amp;gt;SimpleSimController&amp;lt;/code&amp;gt;, and they work identically.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_intervention&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_intervention ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks, releases its schedule shift (if any), and deletes and refunds its pax (if any). No other cost other than pax refunds is issued. This function can be used as a general “despawn the train” feature, not just for exceptional circumstances.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_warp&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_warp ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks and repositions it at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, re-pathing it to its currently scheduled destination (if any), and setting its speed to 0. This is basically a train wormhole. The train keeps its shift and pax, if any.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_drive_to&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_drive_to ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Re-paths the train path to end at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, without any changes to its shift or pax (if any). It is possible for any future &amp;lt;code&amp;gt;queue_train_drive_to&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; to reset this path at any point, losing the destination. “Queue” here is used as part of the SimController API semantics, it does not mean the train keeps a queue of positions to reach. If the path is not interrupted and the train reaches &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; it will re-path itself towards its current scheduled stop, if it has any, or brake to a stop if unassigned. If &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; was also in the stop area set for its current scheduled stop it will also brake to stop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_attach&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_attach ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the attachment of the &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;existing.clone()&amp;lt;/code&amp;gt;) to the &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt;, which must be of one of the following types: &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attached objects can be accessed with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt; at some point in the future. If called from a controller function, the attached object will be accessible after all controller functions are done for a given frame. If called from a task, he attached object will be accessible immediately after the task returns, and before any other task is executed. In other words, tasks are transaction-like, in the sense they view an immutable snapshot of the game state, and any changes they queue are executed before any other task, and then visible from these other tasks.&lt;br /&gt;
&lt;br /&gt;
Attaching an object of a given private struct type when it already exists attached to a &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt; will overwrite it. This is how private data is updated from scripting: by using &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; to copy any existing data, modifying the copy, then calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; to replace the existing data. Therefore it is a good idea to keep your private structs small. Only one instance of a given private struct type can be attached to any particular model object, but you can attach as many different private struct types as you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_erase&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_erase ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the erasure of &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt;, which must obtained using with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt;. Trying to erase temporary objects (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;existing.clone()&amp;lt;/code&amp;gt;) is ignored. The execution of the queued erase commands is analog to the &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; case. In particular a sequences of attach and erase queued from controllers will produce undefined results (impossible to predict which attach and/or erase wins). For example multiple attach from a controller for the same model_obj and private struct type will implicitly pick a singular “winner” attach, but the script does not have any control over which one. Sequences of attach and erase queued from tasks are strictly ordered and isolated, so they produce consistent results, in the same order they were queued in the task script, without any concurrent changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task-and-simcontrollerqueue_task_at&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task and SimController::queue_task_at ===&lt;br /&gt;
&lt;br /&gt;
See [[#Control%20tasks|control tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task_event_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task_event_train ===&lt;br /&gt;
&lt;br /&gt;
See [[#Event%20tasks|event tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;control-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Control tasks ==&lt;br /&gt;
&lt;br /&gt;
Control tasks are a very special kind of command which allows scripts to dynamically queue “future work”, with privileged access to the sim. Scripts with access to &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; can call this function to queue up a task for future script execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; must be of a private struct type which implements &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example { ... }&lt;br /&gt;
pub fn Example::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
For example, a train controller script could decide it needs to delay some decision into a task for data consistency reasons (other controllers are running at the same time), and delegate into a task rather than directly calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ControlTrain extend Train { ... }&lt;br /&gt;
pub fn ControlTrain::control_train(&lt;br /&gt;
    self: &amp;amp;amp;ControlTrain,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    task.train_id = train.id;&lt;br /&gt;
    task.v = some_data_from_somewhere;&lt;br /&gt;
    task.prio = 42; // or something smarter, like from ControlTrain, other objects, etc.&lt;br /&gt;
    sc.queue_task(task);&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
struct Task {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
struct SomeData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
pub fn Task::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    let train &amp;amp;amp;= ctx.db.view(self.train_id) else { return; }&lt;br /&gt;
    if let existing &amp;amp;amp;= ctx.db.view&amp;amp;lt;SomeData&amp;amp;gt;(train) {&lt;br /&gt;
        if existing.prio &amp;amp;gt;= self.prio {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    let data = SomeData::new();&lt;br /&gt;
    data.v = self.v;&lt;br /&gt;
    data.prio = self.prio;&lt;br /&gt;
    sc.queue_attach(train, data);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the previous example, maybe &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; will be called multiple times because multiple &amp;lt;code&amp;gt;ControlTrain::control_train()&amp;lt;/code&amp;gt; instances queued objects of &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;, but each execution will be single threaded, and all its queued &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; commands will be executed just after the call is done and before any other &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; call (for &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; or any other struct type), therefore the algorithm to pick a winner based on an explicit priority works.&lt;br /&gt;
&lt;br /&gt;
As mentioned, task execution is single threaded. The game does not feature a real concurrent database, instead all concurrent access is bespoke and very carefully designed to avoid deadlocks and inconsistencies (this is much faster than a general purpose concurrent database). Scripts also run in this parallel system, but their access to the game state is carefully restricted as explained earlier. But in the end, scripts also need to modify data, and do so in a consistent way. Tasks solve this issue, but do so in the most pessimistic possible way, by being single threaded. Therefore script developers should use them in moderation. Consider the “random winner” semantics of control script queuing first, which are completely free performance wise, before deciding you need a task. It is often the case a concurrent problem reduces to “pick 0 or 1 winners, any winner, but never 2 or more” and the default queue semantics already provide that guarantee for attaching a specific model/private pair.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; is provided with &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt;, therefore it can queue tasks itself. But unlike controller queuing tasks, which are guaranteed to run on the same frame, tasks queued from tasks are guaranteed to ''not'' run on the same frame, on purpose. They are deliberately stored away and forced a delay of 6 sim-seconds. This is to avoid misuse of tasks, and infinite looping.&lt;br /&gt;
&lt;br /&gt;
This behavior might even be desirable in certain scripts, for example if you are developing some stateful signal system and you need some kind of “cleanup” task that makes sure some signal being owned by some train is still the focus of said train. You can deliberately queue tasks for future simulation frames with &amp;lt;code&amp;gt;queue_task_at&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;deadline&amp;lt;/code&amp;gt; is expressed as microseconds since the start of the current save world. You can obtain the current simulation frame &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; value with &amp;lt;code&amp;gt;Extrapolator::clock_us()&amp;lt;/code&amp;gt;, like in this example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;    // schedule task to run 10 sim-s from now&lt;br /&gt;
    sc.queue_task_at(task, ctx.extrapolator.clock_us() + 10000000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;event-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Event tasks ==&lt;br /&gt;
&lt;br /&gt;
Event tasks are a lightweight version of tasks which run when triggered by certain events. Unlike control tasks, event tasks do not have unlimited access to the sim. Instead the run under an &amp;lt;code&amp;gt;EventCtx&amp;lt;/code&amp;gt; like pub struct events, and run multithreaded, at the same time as the C++ code. Unlike the regular &amp;lt;code&amp;gt;event_*&amp;lt;/code&amp;gt; methods, event tasks are queued for execution by script code, not by UI player commands. The design idea of these tasks is to offer a more focused and efficient execution model than &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt;: they are executed immediately once the relevant event happens, in multithreaded context, rather than require passive polling which might even miss certain events and force execution of single thread code.&lt;br /&gt;
&lt;br /&gt;
Any function with a &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; parameter can queue an even task like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Task {...}&lt;br /&gt;
fn f(..., train: &amp;amp;amp;Train, sc: &amp;amp;amp;mut SimController) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    sc.queue_task_event_train(task, train, TaskEventTrain::StopDepart);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
On the next stop departure of the train the &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt; method will be called:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn Task::task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: TaskEventTrain,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == TaskEventTrain::StopDepart {&lt;br /&gt;
        log(&amp;amp;quot;@ departs&amp;amp;quot;, train);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Like control tasks, event tasks encapsulate a single call. If a series of calls are desired, the task can requeue itself by calling &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt;. Event tasks are limited to a maximum of 1 for every possible train-struct-event combination, to avoid leaks. Trying to queue again the same train-struct-event combination will overwrite any existing task. Only the train and motion are provided as parameters. The code can then drill into motion to extract any required information, like shift or line.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-controlctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ControlCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ControlCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    sim: &amp;amp;amp;Sim,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim controller scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects, and associated script stuct objects.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::track_pos_project(self: &amp;amp;amp;DB, pos: &amp;amp;amp;Pos, distance: f64): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return a track position separated by ‘distance’ meters from ‘pos’, in the direction of ‘pos’. If distance is negative it will be in the opposite direction. Can only follow the main track. Merges and dead ends will return a Pos a shorter distance away. Signals are ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view_self(self: &amp;amp;amp;DB): &amp;amp;amp;Script&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-eventctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type EventCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct EventCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim event handler scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line::Stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line::Stop {&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    cars_config: i32,&lt;br /&gt;
    dynamics: Train::Dynamics,&lt;br /&gt;
    hitched_by: Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    station_stop: std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt;,&lt;br /&gt;
    run_stop: std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
    run_dispatch: std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;,&lt;br /&gt;
    hitch: std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motioncachedhitcher&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::CachedHitcher ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::CachedHitcher {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionhitch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Hitch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Hitch {&lt;br /&gt;
    driver_train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    flip: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Train is being hitched by a driver train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
    flip: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionrundispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::RunDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::RunDispatch {&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a line run.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Motion::RunDispatch::current_stop(self: &amp;amp;amp;Motion::RunDispatch, line: &amp;amp;amp;Line): *Line::Stop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionrunstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::RunStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::RunStop {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its line run.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionstationstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::StationStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::StationStop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Schedule::view(self: &amp;amp;amp;Schedule, shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;): *Shift&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns a pointer to the shift, if it’s contained in this schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-script&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Script ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Script {&lt;br /&gt;
    id: ID&amp;amp;lt;Script&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Shift {&lt;br /&gt;
    id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::kind(self: &amp;amp;amp;Signal): mut SignalKind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the signal kind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Track::max_speed(self: &amp;amp;amp;Track): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the min(physical, manual setting) max speed of the track, in m/s.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
    as_purchased: Train::Dynamics,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-traindynamics&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train::Dynamics ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train::Dynamics {&lt;br /&gt;
    max_speed: f32,&lt;br /&gt;
    max_acceleration: f32,&lt;br /&gt;
    max_regular_braking: f32,&lt;br /&gt;
    max_emergency_braking: f32,&lt;br /&gt;
    max_tractive_effort: f32,&lt;br /&gt;
    total_power: f32,&lt;br /&gt;
    empty_mass: f32,&lt;br /&gt;
    length: f32,&lt;br /&gt;
    max_pax: i32,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vec&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;lt;Motion::CachedHitcher&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Hitch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;): *Motion::Hitch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;): *Motion::RunStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::StationStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt;&lt;br /&gt;
): *Motion::StationStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Script&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Shift&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Shift&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Shift&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciterator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;lt;Motion::CachedHitcher&amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator::next(&lt;br /&gt;
    self: &amp;amp;amp;mut Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator&lt;br /&gt;
): *Motion::CachedHitcher&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    idx: i64&lt;br /&gt;
): *Motion::CachedHitcher&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::clock_us(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current microseconds since the creation of this saved game. This is used as the timing root of the simulation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second since 1970-01-01:00:00:00.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_occupation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_reservation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying or reserving the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_occupying(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_reserving(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying or reserving the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
Probe a track position for train reservations and occupations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::view_last&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Extrapolator, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the last frame Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Seconds since 1970-01-01:00:00:00 for Monday 00:00:00 of the current week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestopevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type LineStopEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum LineStopEvent {&lt;br /&gt;
    Arrive,&lt;br /&gt;
    Depart,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
Advance the iterator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftallow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftAllow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftAllow {&lt;br /&gt;
    Allow,&lt;br /&gt;
    Deny,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftEvent {&lt;br /&gt;
    Assign,&lt;br /&gt;
    Unassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftsetup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftSetup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ShiftSetup {&lt;br /&gt;
    skip: bool,&lt;br /&gt;
    match_pos: bool,&lt;br /&gt;
    check_occupation: bool,&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores the context of a train shift lookup.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function wants to change the train path, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signallookaheadresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalLookaheadResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalLookaheadResult {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores extra information associated with the result of the signal lookahead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-sim&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Sim ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Sim {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of the simulation state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Sim::view&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Sim, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A proxy mutable API to the simulation engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    ev: TaskEventTrain&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_hitch(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    driver: &amp;amp;amp;Train,&lt;br /&gt;
    hitcher: &amp;amp;amp;Train,&lt;br /&gt;
    order: i64,&lt;br /&gt;
    flip: bool&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hitch a train to a driver train. The hitched train is emptied of pax and removed from the sim, while its cars are appended to the driver. The order parameter (from -1000 to 1000) determines the hitched train cars position: the driver train is always order 0, so negative values will put the hitch in front of the driver, and positive values behind it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(self: &amp;amp;amp;mut SimController, train: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_run_line(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    arrival_offset_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_configuration(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    config: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_presence_flip(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    flip: bool&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_stop_delay(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    delay_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add extra delay time to a stopped train that has a timed_stop component.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_unhitch(self: &amp;amp;amp;mut SimController, hitcher: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Remove the hitched state from a train. It will become an unspawned, unassigned train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simplesimcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimpleSimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimpleSimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A limited API version of SimController.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimpleSimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimpleSimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-taskeventtrain&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TaskEventTrain ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum TaskEventTrain {&lt;br /&gt;
    StopArrive,&lt;br /&gt;
    StopDepart,&lt;br /&gt;
    ShiftAssign,&lt;br /&gt;
    ShiftUnassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=562</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=562"/>
		<updated>2026-02-06T18:00:35Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used in game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration, integer division or arbitrary setting of pointers and references, and most data exposed to scripts is read-only, strictly enforced by the language. Any expression result which could result in an out of bounds or invalid memory access must be checked for validity, and the API design together with the type system enforces it.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
pub struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;SpeedTrap,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- VisMod? 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' ColonNAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Script&amp;lt;/code&amp;gt; (with restrictions)&lt;br /&gt;
&lt;br /&gt;
Structs extending game types for player extensions must be declared as &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt;. When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
To read struct objects from script code they must be looked up using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API. Therefore only functions provided with &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt; object (or a context object with contains &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt;) can look up these objects. But you can pass around &amp;lt;code&amp;gt;DB&amp;amp;amp;&amp;lt;/code&amp;gt; as a parameter without any lifetime restrictions, since it’s a purely read only API. This API also works for non-pub structs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= ctx.db.view&amp;amp;lt;Example&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    log(&amp;amp;quot;v = @&amp;amp;quot;, config.v);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;pub-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== pub structs ====&lt;br /&gt;
&lt;br /&gt;
As explained earlier, &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs are the user interface of your scripts. They are exposed in the UI as input forms, and their &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;s can give some control over this rendering. Conceptually they are owned by the player of the game as part of the game object database, by attaching them to a game model object in the database, not the script. Scripts do not have any capability to create, edit or delete objects of &amp;lt;code&amp;gt;pub struct&amp;lt;/code&amp;gt;s. It is always the player who decides when to create a new object of these structs by interacting in the UI. Scripts can then read, and only read, the content of these objects, by using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API presented earlier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs have a very powerful capability: they have limited support for forward schema evolution. This means that the script developer can add to, and reorder, fields in &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, and the game runtime will be able keep the contents of the other fields intact. This is very important to respect the input data by the player. If you rename &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs or their fields, or change their types, the player input data will be lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;non-pub-or-private-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Non-pub (or private) structs ====&lt;br /&gt;
&lt;br /&gt;
Non-&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, also called private structs, are conceptually owned by the script as a part of the simulation, not the player. Their contents are assumed to be a black box by the rest of the game. Scripts are allowed to create and modify objects of these structs during their execution, which are automatically deleted at the end of the simulation frame. It is also possible to attach these structs to existing game model objects to extend their lifetime beyond the current frame. In this case their lifetime becomes the same as the game object, and they can be retrieved in later frames for reading, deleted or overwritten as desired.&lt;br /&gt;
&lt;br /&gt;
Private structs ''do not support schema evolution''. Changing field types, field names, reordering of fields, even just adding new fields at the end, will always result in losing all existing attached objects of the given struct. Some operations like resetting the simulation will also erase attached objects, because they are considered simulation state, not player created objects.&lt;br /&gt;
&lt;br /&gt;
Private structs support dynamic memory allocation. All private struct definitions automatically create a &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; method for the struct:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct PrivData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let ro &amp;amp;amp;= ctx.db.view&amp;amp;lt;PrivData&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    let rw &amp;amp;amp;mut= ro.clone();&lt;br /&gt;
    rw.v = 100;&lt;br /&gt;
    let empty &amp;amp;amp;mut= PrivData::new();&lt;br /&gt;
    empty.v = 200;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The objects allocated by &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; are always deleted at the end of the current simulation frame. Their lifetime can be extended beyond the current frame by attaching them to a game object, like &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, so their lifetime becomes the same as the attached object. The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API has methods for attaching and erasing these object.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;host-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Host structs ====&lt;br /&gt;
&lt;br /&gt;
Many of the exposed game APIs are also based around structs. These structs do not follow any of the previous rules. Some have special capabilities, for example simple structs like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt; are ''value objects'': they can be copied and passed around like any &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; would. Some others are strictly locked down and serve as very little beyond a way to keep a pointer safe. In general, when working with game API structs, assume they are what would be called ''move only'' in C++. And NimbyScript has no move operator or semantics, so in essence assume they are immutable, immobile references, except when documented otherwise (like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As an aside, all script declared &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; or not) are also always ''move only'', and always “owned” by some external entity. This is why the APIs for their manipulation are always based on pointers and references, even for private structs. It is not possible to create plain, stack allocated values of script structs, or to use them as fields in structs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version:&lt;br /&gt;
&lt;br /&gt;
* Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
* Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums)&lt;br /&gt;
* For pub structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* For private structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In pub structs these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types. &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; will also display a small list editor. Keep in mind the correct type is &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;Vec&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types. It will be displayed as the input widget label.&lt;br /&gt;
* The &amp;lt;code&amp;gt;description&amp;lt;/code&amp;gt; meta field is accepted for all field types. It will be displayed as the input widget tooltip.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- 'let' BindBody 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- 'let' BindBody ';'&lt;br /&gt;
BindBody    &amp;amp;lt;- NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' 'let' BindBody BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- ColonNAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere pointer types cannot be dereferenced, therefore cannot be used in dot expressions. The exception is the built-in function &amp;lt;code&amp;gt;is_valid(ptr): bool&amp;lt;/code&amp;gt;, which is usable with any pointer type.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;extensions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Extensions =&lt;br /&gt;
&lt;br /&gt;
Extending game database struct data with &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt; can also be used to extend the game code. The mechanism to do so is to first declare a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;ing a game database object (with or without fields). Then create a specifically named and parametrized function which will be called by the game under certain situations, for certain kinds of objects.&lt;br /&gt;
&lt;br /&gt;
All extension functions take a &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter which is a reference to the struct which it is method of, called &amp;lt;code&amp;gt;Example&amp;lt;/code&amp;gt; in the following sections. Replace it with your struct name. The rest of the parameters are fixed and must be reproduced exactly as-is.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
Event functions are called as part of the core simulation engine. They are meant to be focused in features and quick to execute. These functions might be called thousands of times per simulation frame, including multiple redundant times. Their capability to change the simulation behavior is usually very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_check&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_check ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails, or if another script call returns &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_lookahead&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_lookahead ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_lookahead(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    train_distance: f64,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalLookaheadResult&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; function at regular intervals for each signal 15km ahead of the train path. It is called for all signals, until one of these conditions hold:&lt;br /&gt;
&lt;br /&gt;
* One of the signals path checks as &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;&lt;br /&gt;
* Another train is found&lt;br /&gt;
* The train stop is found&lt;br /&gt;
* 15km have been checked&lt;br /&gt;
&lt;br /&gt;
For both &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; signals, your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; will be called, and you can check the path find result in &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;, and the distance from the train in &amp;lt;code&amp;gt;train_distance&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; allows to set a maximum speed for the train, which goes into effect immediately. It must be expressed as m/s. This works from any distance and past any amount of signals between the train and the caller signal. If multiple signals in the lookahead path return a &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt;, the slowest speed is picked. If no &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt; is set, or it is 0, the result is ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; default value is 0, which is considered invalid and will be ignored. To stop the train at the signal implement &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_change_path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_change_path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_change_path(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The current path check result of this signal for the passed train is passed as &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;. This already includes any results from &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_pass_by&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_pass_by ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_pass_by(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; function on the exact simulation frame a train passes by the exact point of the signal on the track.&lt;br /&gt;
&lt;br /&gt;
This function has no return result. Instead, since it has a predictably low call rate compared to the other events, it is the only event function with access to the powerful &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_marker_reserved&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_marker_reserved ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given marker signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; any time the reservation check algorithm is tracing a path which goes over the marker signal, on any direction, giving it the chance to report an arbitrary train as the reserver of that point on the track.&lt;br /&gt;
&lt;br /&gt;
This signal has a potential huge call rate, and for this reason it is given very little access to the APIs. The intention is that all the state required by this signal is calculated somewhere else and attached to the signal as a private struct object, or to some object reachable from it. Don’t worry about filtering for the “same train” cases, this is automatically done.&lt;br /&gt;
&lt;br /&gt;
If no reservation is desired, use the &amp;lt;code&amp;gt;empty&amp;lt;/code&amp;gt; global method available in all &amp;lt;code&amp;gt;ID&amp;amp;lt;Class&amp;amp;gt;&amp;lt;/code&amp;gt; types: &amp;lt;code&amp;gt;return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {}&lt;br /&gt;
struct Owner {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; {&lt;br /&gt;
    // some other, more full featured script function has attached Owner to this signal,&lt;br /&gt;
    // or not, so we need to check first&lt;br /&gt;
    if let owner &amp;amp;amp;= db.view&amp;amp;lt;Owner&amp;amp;gt;(signal) {&lt;br /&gt;
        if is_valid(db.view(owner.train_id)) {&lt;br /&gt;
            return owner.train_id;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_texture_state&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_texture_state ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_texture_state(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    clock_us: i64&lt;br /&gt;
): i64 { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment, when the game UI needs to query what is the current signal texture state index, it will call your &amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt;, with some potential caching to keep the call rate lower. In any case the call rate of this function is potentially very large when the user zooms out the map, so make sure to keep its code as efficient as possible. For this same reason it is given very little access to the APIs. &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; is the number of sim-microseconds since the current save was created, you use it with the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; functions to make animations.&lt;br /&gt;
&lt;br /&gt;
The return value indicates which signal texture state is to be used. If it’s -1 or lower, the default algorithm will be used to select the texture index. If it’s 0 or larger, it will select the texture in the same order as the &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; lines in the &amp;lt;code&amp;gt;SignalTextures&amp;lt;/code&amp;gt;. Larger values than the number of states will be clamped to the last state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_setup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_setup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_setup(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ss: &amp;amp;amp;mut ShiftSetup&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when an unassigned train decides to lookup a new shift to run, it will first call &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The parameter &amp;lt;code&amp;gt;ss&amp;lt;/code&amp;gt; is both an input and output parameter. It is initialized with the current, relevant data for the given train state, and &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; can then change it, to influence which shifts will be considered by the shift selection algorithm. It can change the train position used for matching, the time used for matching, and disable the check for reservations. For matched shifts which do not correspond to the current train position, the Extrapolator system will automatically pathfind a temporary milestone for the train, like other path-changing features. &amp;lt;code&amp;gt;ShiftSetup::epoch_s&amp;lt;/code&amp;gt; allowed range is between minus one week and plus one week from the current simulation time, with values outside this range being clamped into it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_allow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_allow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_allow(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    run: &amp;amp;amp;Run,&lt;br /&gt;
    stop_idx: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    pose: &amp;amp;amp;Pose&lt;br /&gt;
): ShiftAllow { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when the shift selection algorithm fins a valid shift for the given train, it will call &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; with all the relevant data. The return of the function can then allow or deny the shift. If the shift is denied, the algorithm will resume immediately, trying other shifts&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are independent from each other, and can be used in any combination.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;linestop-event_line_stop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Line::Stop event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestStop extend Line::Stop {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestStop::event_line_stop(&lt;br /&gt;
    self: &amp;amp;amp;TestStop,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == LineStopEvent::Arrive {&lt;br /&gt;
        log(&amp;amp;quot;@ arrives @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ departs @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given line stop in the line editor. From that moment, when any train arrives or departs said line stop, &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LineStopEvent::Depart&amp;lt;/code&amp;gt; to distinguish between arrival and departure. Waypoints are only called for &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt;. Shift-less trains are also called.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;shift-event_shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Shift event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestShift extend Shift {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestShift::event_shift(&lt;br /&gt;
    self: &amp;amp;amp;TestShift,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == ShiftEvent::Assign {&lt;br /&gt;
        log(&amp;amp;quot;@ assigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ unassigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given schedule shift in the line editor. From that moment, when any train is assigned to the shift, or becomes unassigned from the shift, &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;ShiftEvent::Assign&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ShiftEvent::Unassign&amp;lt;/code&amp;gt; to distinguish between assignation and unassignation. The &amp;lt;code&amp;gt;Assign&amp;lt;/code&amp;gt; event is called just after &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been set up, so it already has all the shift and run information. The &amp;lt;code&amp;gt;Unassign&amp;lt;/code&amp;gt; event is called just before &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been cleared of all shift and run information so the script has access to as much information as possible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;global-events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Global events ==&lt;br /&gt;
&lt;br /&gt;
Like event functions of struct extensions, global events are called as part of the core simulation engine when a specific event occurs, but they are not associated to any struct. Instead they are public top level functions with the signature given in this document. Global event functions are always called if they exist in a script and the event occurs.&lt;br /&gt;
&lt;br /&gt;
=== global_event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn global_event_line_stop(&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    log(&amp;amp;quot;global_event_line_stop: @ on line @&amp;amp;quot;, train, line);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Arguments and conditions are identical to &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt;, except there is no &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter.&lt;br /&gt;
&lt;br /&gt;
=== global_event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn global_event_shift(&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    log(&amp;amp;quot;global_event_shift: @ on sched @&amp;amp;quot;, train, sched);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Arguments and conditions are identical to &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt;, except there is no &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;controllers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Controllers ==&lt;br /&gt;
&lt;br /&gt;
Controller functions are called at a low frame rate compared to the overall simulation, with an (unchangeable) rate of once in 6 sim-seconds. They do not need any specific event or trigger to run, other than their enforced timer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-control_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train control_train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct HateDepots extend Train {}&lt;br /&gt;
pub fn HateDepots::control_train(&lt;br /&gt;
    self: &amp;amp;amp;HateDepots,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    // train is already removed from the tracks, don't interfere with potential attempts at shift assignation&lt;br /&gt;
    if !is_valid(motion.presence.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is running a schedule, don't interfere&lt;br /&gt;
    if is_valid(motion.schedule_dispatch.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is present, but it is not running a schedule, so despawn it&lt;br /&gt;
    sc.queue_train_intervention(train);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The train motion engine will call train controllers in the multithreaded phase, as part of the regular train motion extrapolator, after all the C++ code is done for a frame for a particular train, but before any queued commands are executed. Command execution will only happen after all train controllers for a given frame are done. In other words, train controllers queue up work to be executed by the sim. They never directly change the sim in any way, allowing train controller execution to be fully parallel.&lt;br /&gt;
&lt;br /&gt;
After all controllers are run, and all their non-task commands are executed, and then tasks are executed. Read more about tasks later on. Any tasks with a deadline which expired in this frame a run at this time too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontroller-command-queue&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== SimController command queue ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; object implements an API to control the simulation, including modification of some parameters and behaviors. It is also responsible for attaching and erasing private struct data from game objects, on behalf of scripts. The execution of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; is based on a command queue. Every call queues a command and returns immediately to the script code, without making any changes to the game state. Therefore the game state never changes while the script code is running.&lt;br /&gt;
&lt;br /&gt;
Commands queued from events and &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt; are executed asynchronously, there is no guaranteed order of execution! You must prepare your code and data for this design. For stand alone tasks scripts commands are executed in order and in isolation. You can queue up tasks from event and control scripts when you need to guarantee data consistency beyond “pick a random winner”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SimpleSimController&amp;lt;/code&amp;gt; is a cut down version of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; for high frequency events like &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt;. The reference in the second part of this document lists which &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; functions are available in &amp;lt;code&amp;gt;SimpleSimController&amp;lt;/code&amp;gt;, and they work identically.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_intervention&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_intervention ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks, releases its schedule shift (if any), and deletes and refunds its pax (if any). No other cost other than pax refunds is issued. This function can be used as a general “despawn the train” feature, not just for exceptional circumstances.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_warp&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_warp ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks and repositions it at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, re-pathing it to its currently scheduled destination (if any), and setting its speed to 0. This is basically a train wormhole. The train keeps its shift and pax, if any.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_drive_to&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_drive_to ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Re-paths the train path to end at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, without any changes to its shift or pax (if any). It is possible for any future &amp;lt;code&amp;gt;queue_train_drive_to&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; to reset this path at any point, losing the destination. “Queue” here is used as part of the SimController API semantics, it does not mean the train keeps a queue of positions to reach. If the path is not interrupted and the train reaches &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; it will re-path itself towards its current scheduled stop, if it has any, or brake to a stop if unassigned. If &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; was also in the stop area set for its current scheduled stop it will also brake to stop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_attach&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_attach ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the attachment of the &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;existing.clone()&amp;lt;/code&amp;gt;) to the &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt;, which must be of one of the following types: &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attached objects can be accessed with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt; at some point in the future. If called from a controller function, the attached object will be accessible after all controller functions are done for a given frame. If called from a task, he attached object will be accessible immediately after the task returns, and before any other task is executed. In other words, tasks are transaction-like, in the sense they view an immutable snapshot of the game state, and any changes they queue are executed before any other task, and then visible from these other tasks.&lt;br /&gt;
&lt;br /&gt;
Attaching an object of a given private struct type when it already exists attached to a &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt; will overwrite it. This is how private data is updated from scripting: by using &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; to copy any existing data, modifying the copy, then calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; to replace the existing data. Therefore it is a good idea to keep your private structs small. Only one instance of a given private struct type can be attached to any particular model object, but you can attach as many different private struct types as you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_erase&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_erase ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the erasure of &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt;, which must obtained using with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt;. Trying to erase temporary objects (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;existing.clone()&amp;lt;/code&amp;gt;) is ignored. The execution of the queued erase commands is analog to the &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; case. In particular a sequences of attach and erase queued from controllers will produce undefined results (impossible to predict which attach and/or erase wins). For example multiple attach from a controller for the same model_obj and private struct type will implicitly pick a singular “winner” attach, but the script does not have any control over which one. Sequences of attach and erase queued from tasks are strictly ordered and isolated, so they produce consistent results, in the same order they were queued in the task script, without any concurrent changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task-and-simcontrollerqueue_task_at&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task and SimController::queue_task_at ===&lt;br /&gt;
&lt;br /&gt;
See [[#Control%20tasks|control tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task_event_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task_event_train ===&lt;br /&gt;
&lt;br /&gt;
See [[#Event%20tasks|event tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;control-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Control tasks ==&lt;br /&gt;
&lt;br /&gt;
Control tasks are a very special kind of command which allows scripts to dynamically queue “future work”, with privileged access to the sim. Scripts with access to &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; can call this function to queue up a task for future script execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; must be of a private struct type which implements &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example { ... }&lt;br /&gt;
pub fn Example::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
For example, a train controller script could decide it needs to delay some decision into a task for data consistency reasons (other controllers are running at the same time), and delegate into a task rather than directly calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ControlTrain extend Train { ... }&lt;br /&gt;
pub fn ControlTrain::control_train(&lt;br /&gt;
    self: &amp;amp;amp;ControlTrain,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    task.train_id = train.id;&lt;br /&gt;
    task.v = some_data_from_somewhere;&lt;br /&gt;
    task.prio = 42; // or something smarter, like from ControlTrain, other objects, etc.&lt;br /&gt;
    sc.queue_task(task);&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
struct Task {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
struct SomeData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
pub fn Task::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    let train &amp;amp;amp;= ctx.db.view(self.train_id) else { return; }&lt;br /&gt;
    if let existing &amp;amp;amp;= ctx.db.view&amp;amp;lt;SomeData&amp;amp;gt;(train) {&lt;br /&gt;
        if existing.prio &amp;amp;gt;= self.prio {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    let data = SomeData::new();&lt;br /&gt;
    data.v = self.v;&lt;br /&gt;
    data.prio = self.prio;&lt;br /&gt;
    sc.queue_attach(train, data);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the previous example, maybe &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; will be called multiple times because multiple &amp;lt;code&amp;gt;ControlTrain::control_train()&amp;lt;/code&amp;gt; instances queued objects of &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;, but each execution will be single threaded, and all its queued &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; commands will be executed just after the call is done and before any other &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; call (for &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; or any other struct type), therefore the algorithm to pick a winner based on an explicit priority works.&lt;br /&gt;
&lt;br /&gt;
As mentioned, task execution is single threaded. The game does not feature a real concurrent database, instead all concurrent access is bespoke and very carefully designed to avoid deadlocks and inconsistencies (this is much faster than a general purpose concurrent database). Scripts also run in this parallel system, but their access to the game state is carefully restricted as explained earlier. But in the end, scripts also need to modify data, and do so in a consistent way. Tasks solve this issue, but do so in the most pessimistic possible way, by being single threaded. Therefore script developers should use them in moderation. Consider the “random winner” semantics of control script queuing first, which are completely free performance wise, before deciding you need a task. It is often the case a concurrent problem reduces to “pick 0 or 1 winners, any winner, but never 2 or more” and the default queue semantics already provide that guarantee for attaching a specific model/private pair.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; is provided with &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt;, therefore it can queue tasks itself. But unlike controller queuing tasks, which are guaranteed to run on the same frame, tasks queued from tasks are guaranteed to ''not'' run on the same frame, on purpose. They are deliberately stored away and forced a delay of 6 sim-seconds. This is to avoid misuse of tasks, and infinite looping.&lt;br /&gt;
&lt;br /&gt;
This behavior might even be desirable in certain scripts, for example if you are developing some stateful signal system and you need some kind of “cleanup” task that makes sure some signal being owned by some train is still the focus of said train. You can deliberately queue tasks for future simulation frames with &amp;lt;code&amp;gt;queue_task_at&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;deadline&amp;lt;/code&amp;gt; is expressed as microseconds since the start of the current save world. You can obtain the current simulation frame &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; value with &amp;lt;code&amp;gt;Extrapolator::clock_us()&amp;lt;/code&amp;gt;, like in this example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;    // schedule task to run 10 sim-s from now&lt;br /&gt;
    sc.queue_task_at(task, ctx.extrapolator.clock_us() + 10000000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;event-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Event tasks ==&lt;br /&gt;
&lt;br /&gt;
Event tasks are a lightweight version of tasks which run when triggered by certain events. Unlike control tasks, event tasks do not have unlimited access to the sim. Instead the run under an &amp;lt;code&amp;gt;EventCtx&amp;lt;/code&amp;gt; like pub struct events, and run multithreaded, at the same time as the C++ code. Unlike the regular &amp;lt;code&amp;gt;event_*&amp;lt;/code&amp;gt; methods, event tasks are queued for execution by script code, not by UI player commands. The design idea of these tasks is to offer a more focused and efficient execution model than &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt;: they are executed immediately once the relevant event happens, in multithreaded context, rather than require passive polling which might even miss certain events and force execution of single thread code.&lt;br /&gt;
&lt;br /&gt;
Any function with a &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; parameter can queue an even task like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Task {...}&lt;br /&gt;
fn f(..., train: &amp;amp;amp;Train, sc: &amp;amp;amp;mut SimController) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    sc.queue_task_event_train(task, train, TaskEventTrain::StopDepart);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
On the next stop departure of the train the &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt; method will be called:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn Task::task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: TaskEventTrain,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == TaskEventTrain::StopDepart {&lt;br /&gt;
        log(&amp;amp;quot;@ departs&amp;amp;quot;, train);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Like control tasks, event tasks encapsulate a single call. If a series of calls are desired, the task can requeue itself by calling &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt;. Event tasks are limited to a maximum of 1 for every possible train-struct-event combination, to avoid leaks. Trying to queue again the same train-struct-event combination will overwrite any existing task. Only the train and motion are provided as parameters. The code can then drill into motion to extract any required information, like shift or line.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-controlctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ControlCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ControlCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    sim: &amp;amp;amp;Sim,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim controller scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects, and associated script stuct objects.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::track_pos_project(self: &amp;amp;amp;DB, pos: &amp;amp;amp;Pos, distance: f64): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return a track position separated by ‘distance’ meters from ‘pos’, in the direction of ‘pos’. If distance is negative it will be in the opposite direction. Can only follow the main track. Merges and dead ends will return a Pos a shorter distance away. Signals are ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view_self(self: &amp;amp;amp;DB): &amp;amp;amp;Script&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-eventctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type EventCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct EventCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim event handler scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line::Stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line::Stop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    cars_config: i32,&lt;br /&gt;
    dynamics: Train::Dynamics,&lt;br /&gt;
    hitched_by: Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    station_stop: std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;,&lt;br /&gt;
    run_stop: std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
    run_dispatch: std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;,&lt;br /&gt;
    hitch: std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motioncachedhitcher&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::CachedHitcher ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::CachedHitcher {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionhitch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Hitch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Hitch {&lt;br /&gt;
    driver_train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    flip: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Train is being hitched by a driver train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
    flip: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionrundispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::RunDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::RunDispatch {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a line run.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Motion::RunDispatch::current_stop(self: &amp;amp;amp;Motion::RunDispatch, line: &amp;amp;amp;Line): *Line::Stop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionstationstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::StationStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::StationStop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Schedule::view(self: &amp;amp;amp;Schedule, shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;): *Shift&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns a pointer to the shift, if it’s contained in this schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-script&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Script ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Script {&lt;br /&gt;
    id: ID&amp;amp;lt;Script&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Shift {&lt;br /&gt;
    id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::kind(self: &amp;amp;amp;Signal): mut SignalKind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the signal kind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Track::max_speed(self: &amp;amp;amp;Track): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the min(physical, manual setting) max speed of the track, in m/s.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
    as_purchased: Train::Dynamics,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-traindynamics&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train::Dynamics ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train::Dynamics {&lt;br /&gt;
    max_speed: f32,&lt;br /&gt;
    max_acceleration: f32,&lt;br /&gt;
    max_regular_braking: f32,&lt;br /&gt;
    max_emergency_braking: f32,&lt;br /&gt;
    max_tractive_effort: f32,&lt;br /&gt;
    total_power: f32,&lt;br /&gt;
    empty_mass: f32,&lt;br /&gt;
    length: f32,&lt;br /&gt;
    max_pax: i32,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vec&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;lt;Motion::CachedHitcher&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Hitch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;): *Motion::Hitch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStationEvent&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;&lt;br /&gt;
): *Motion::StationStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Script&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Shift&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Shift&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Shift&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciterator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;lt;Motion::CachedHitcher&amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator::next(&lt;br /&gt;
    self: &amp;amp;amp;mut Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator&lt;br /&gt;
): *Motion::CachedHitcher&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    idx: i64&lt;br /&gt;
): *Motion::CachedHitcher&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::clock_us(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current microseconds since the creation of this saved game. This is used as the timing root of the simulation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second since 1970-01-01:00:00:00.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_occupation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_reservation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying or reserving the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_occupying(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_reserving(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying or reserving the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
Probe a track position for train reservations and occupations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::view_last&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Extrapolator, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the last frame Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Seconds since 1970-01-01:00:00:00 for Monday 00:00:00 of the current week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestopevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type LineStopEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum LineStopEvent {&lt;br /&gt;
    Arrive,&lt;br /&gt;
    Depart,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
Advance the iterator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftallow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftAllow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftAllow {&lt;br /&gt;
    Allow,&lt;br /&gt;
    Deny,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftEvent {&lt;br /&gt;
    Assign,&lt;br /&gt;
    Unassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftsetup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftSetup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ShiftSetup {&lt;br /&gt;
    skip: bool,&lt;br /&gt;
    match_pos: bool,&lt;br /&gt;
    check_occupation: bool,&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores the context of a train shift lookup.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function wants to change the train path, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signallookaheadresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalLookaheadResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalLookaheadResult {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores extra information associated with the result of the signal lookahead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-sim&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Sim ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Sim {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of the simulation state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Sim::view&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Sim, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A proxy mutable API to the simulation engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    ev: TaskEventTrain&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_hitch(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    driver: &amp;amp;amp;Train,&lt;br /&gt;
    hitcher: &amp;amp;amp;Train,&lt;br /&gt;
    order: i64,&lt;br /&gt;
    flip: bool&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hitch a train to a driver train. The hitched train is emptied of pax and removed from the sim, while its cars are appended to the driver. The order parameter (from -1000 to 1000) determines the hitched train cars position: the driver train is always order 0, so negative values will put the hitch in front of the driver, and positive values behind it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(self: &amp;amp;amp;mut SimController, train: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_run_line(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    arrival_offset_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_configuration(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    config: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_presence_flip(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    flip: bool&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_stop_delay(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    delay_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add extra delay time to a stopped train that has a timed_stop component.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_unhitch(self: &amp;amp;amp;mut SimController, hitcher: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Remove the hitched state from a train. It will become an unspawned, unassigned train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simplesimcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimpleSimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimpleSimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A limited API version of SimController.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimpleSimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimpleSimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-taskeventtrain&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TaskEventTrain ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum TaskEventTrain {&lt;br /&gt;
    StopArrive,&lt;br /&gt;
    StopDepart,&lt;br /&gt;
    ShiftAssign,&lt;br /&gt;
    ShiftUnassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=561</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=561"/>
		<updated>2026-02-02T10:48:30Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used in game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration, integer division or arbitrary setting of pointers and references, and most data exposed to scripts is read-only, strictly enforced by the language. Any expression result which could result in an out of bounds or invalid memory access must be checked for validity, and the API design together with the type system enforces it.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
pub struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;SpeedTrap,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- VisMod? 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' ColonNAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Script&amp;lt;/code&amp;gt; (with restrictions)&lt;br /&gt;
&lt;br /&gt;
Structs extending game types for player extensions must be declared as &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt;. When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
To read struct objects from script code they must be looked up using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API. Therefore only functions provided with &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt; object (or a context object with contains &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt;) can look up these objects. But you can pass around &amp;lt;code&amp;gt;DB&amp;amp;amp;&amp;lt;/code&amp;gt; as a parameter without any lifetime restrictions, since it’s a purely read only API. This API also works for non-pub structs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= ctx.db.view&amp;amp;lt;Example&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    log(&amp;amp;quot;v = @&amp;amp;quot;, config.v);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;pub-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== pub structs ====&lt;br /&gt;
&lt;br /&gt;
As explained earlier, &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs are the user interface of your scripts. They are exposed in the UI as input forms, and their &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;s can give some control over this rendering. Conceptually they are owned by the player of the game as part of the game object database, by attaching them to a game model object in the database, not the script. Scripts do not have any capability to create, edit or delete objects of &amp;lt;code&amp;gt;pub struct&amp;lt;/code&amp;gt;s. It is always the player who decides when to create a new object of these structs by interacting in the UI. Scripts can then read, and only read, the content of these objects, by using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API presented earlier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs have a very powerful capability: they have limited support for forward schema evolution. This means that the script developer can add to, and reorder, fields in &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, and the game runtime will be able keep the contents of the other fields intact. This is very important to respect the input data by the player. If you rename &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs or their fields, or change their types, the player input data will be lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;non-pub-or-private-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Non-pub (or private) structs ====&lt;br /&gt;
&lt;br /&gt;
Non-&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, also called private structs, are conceptually owned by the script as a part of the simulation, not the player. Their contents are assumed to be a black box by the rest of the game. Scripts are allowed to create and modify objects of these structs during their execution, which are automatically deleted at the end of the simulation frame. It is also possible to attach these structs to existing game model objects to extend their lifetime beyond the current frame. In this case their lifetime becomes the same as the game object, and they can be retrieved in later frames for reading, deleted or overwritten as desired.&lt;br /&gt;
&lt;br /&gt;
Private structs ''do not support schema evolution''. Changing field types, field names, reordering of fields, even just adding new fields at the end, will always result in losing all existing attached objects of the given struct. Some operations like resetting the simulation will also erase attached objects, because they are considered simulation state, not player created objects.&lt;br /&gt;
&lt;br /&gt;
Private structs support dynamic memory allocation. All private struct definitions automatically create a &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; method for the struct:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct PrivData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let ro &amp;amp;amp;= ctx.db.view&amp;amp;lt;PrivData&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    let rw &amp;amp;amp;mut= ro.clone();&lt;br /&gt;
    rw.v = 100;&lt;br /&gt;
    let empty &amp;amp;amp;mut= PrivData::new();&lt;br /&gt;
    empty.v = 200;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The objects allocated by &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; are always deleted at the end of the current simulation frame. Their lifetime can be extended beyond the current frame by attaching them to a game object, like &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, so their lifetime becomes the same as the attached object. The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API has methods for attaching and erasing these object.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;host-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Host structs ====&lt;br /&gt;
&lt;br /&gt;
Many of the exposed game APIs are also based around structs. These structs do not follow any of the previous rules. Some have special capabilities, for example simple structs like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt; are ''value objects'': they can be copied and passed around like any &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; would. Some others are strictly locked down and serve as very little beyond a way to keep a pointer safe. In general, when working with game API structs, assume they are what would be called ''move only'' in C++. And NimbyScript has no move operator or semantics, so in essence assume they are immutable, immobile references, except when documented otherwise (like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As an aside, all script declared &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; or not) are also always ''move only'', and always “owned” by some external entity. This is why the APIs for their manipulation are always based on pointers and references, even for private structs. It is not possible to create plain, stack allocated values of script structs, or to use them as fields in structs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version:&lt;br /&gt;
&lt;br /&gt;
* Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
* Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums)&lt;br /&gt;
* For pub structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* For private structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In pub structs these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types. &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; will also display a small list editor. Keep in mind the correct type is &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;Vec&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- 'let' BindBody 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- 'let' BindBody ';'&lt;br /&gt;
BindBody    &amp;amp;lt;- NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' 'let' BindBody BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- ColonNAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere pointer types cannot be dereferenced, therefore cannot be used in dot expressions. The exception is the built-in function &amp;lt;code&amp;gt;is_valid(ptr): bool&amp;lt;/code&amp;gt;, which is usable with any pointer type.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;extensions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Extensions =&lt;br /&gt;
&lt;br /&gt;
Extending game database struct data with &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt; can also be used to extend the game code. The mechanism to do so is to first declare a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;ing a game database object (with or without fields). Then create a specifically named and parametrized function which will be called by the game under certain situations, for certain kinds of objects.&lt;br /&gt;
&lt;br /&gt;
All extension functions take a &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter which is a reference to the struct which it is method of, called &amp;lt;code&amp;gt;Example&amp;lt;/code&amp;gt; in the following sections. Replace it with your struct name. The rest of the parameters are fixed and must be reproduced exactly as-is.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
Event functions are called as part of the core simulation engine. They are meant to be focused in features and quick to execute. These functions might be called thousands of times per simulation frame, including multiple redundant times. Their capability to change the simulation behavior is usually very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_check&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_check ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails, or if another script call returns &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_lookahead&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_lookahead ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_lookahead(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    train_distance: f64,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalLookaheadResult&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; function at regular intervals for each signal 15km ahead of the train path. It is called for all signals, until one of these conditions hold:&lt;br /&gt;
&lt;br /&gt;
* One of the signals path checks as &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;&lt;br /&gt;
* Another train is found&lt;br /&gt;
* The train stop is found&lt;br /&gt;
* 15km have been checked&lt;br /&gt;
&lt;br /&gt;
For both &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; signals, your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; will be called, and you can check the path find result in &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;, and the distance from the train in &amp;lt;code&amp;gt;train_distance&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; allows to set a maximum speed for the train, which goes into effect immediately. This works from any distance and past any amount of signals between the train and the caller signal. If multiple signals in the lookahead path return a &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt;, the slowest speed is picked. If no &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt; is set, or it is 0, the result is ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; default value is 0, which is considered invalid and will be ignored. To stop the train at the signal implement &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_change_path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_change_path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_change_path(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The current path check result of this signal for the passed train is passed as &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;. This already includes any results from &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_pass_by&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_pass_by ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_pass_by(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; function on the exact simulation frame a train passes by the exact point of the signal on the track.&lt;br /&gt;
&lt;br /&gt;
This function has no return result. Instead, since it has a predictably low call rate compared to the other events, it is the only event function with access to the powerful &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_marker_reserved&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_marker_reserved ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given marker signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; any time the reservation check algorithm is tracing a path which goes over the marker signal, on any direction, giving it the chance to report an arbitrary train as the reserver of that point on the track.&lt;br /&gt;
&lt;br /&gt;
This signal has a potential huge call rate, and for this reason it is given very little access to the APIs. The intention is that all the state required by this signal is calculated somewhere else and attached to the signal as a private struct object, or to some object reachable from it. Don’t worry about filtering for the “same train” cases, this is automatically done.&lt;br /&gt;
&lt;br /&gt;
If no reservation is desired, use the &amp;lt;code&amp;gt;empty&amp;lt;/code&amp;gt; global method available in all &amp;lt;code&amp;gt;ID&amp;amp;lt;Class&amp;amp;gt;&amp;lt;/code&amp;gt; types: &amp;lt;code&amp;gt;return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {}&lt;br /&gt;
struct Owner {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; {&lt;br /&gt;
    // some other, more full featured script function has attached Owner to this signal,&lt;br /&gt;
    // or not, so we need to check first&lt;br /&gt;
    if let owner &amp;amp;amp;= db.view&amp;amp;lt;Owner&amp;amp;gt;(signal) {&lt;br /&gt;
        if is_valid(db.view(owner.train_id)) {&lt;br /&gt;
            return owner.train_id;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_texture_state&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_texture_state ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_texture_state(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    clock_us: i64&lt;br /&gt;
): i64 { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment, when the game UI needs to query what is the current signal texture state index, it will call your &amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt;, with some potential caching to keep the call rate lower. In any case the call rate of this function is potentially very large when the user zooms out the map, so make sure to keep its code as efficient as possible. For this same reason it is given very little access to the APIs. &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; is the number of sim-microseconds since the current save was created, you use it with the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; functions to make animations.&lt;br /&gt;
&lt;br /&gt;
The return value indicates which signal texture state is to be used. If it’s -1 or lower, the default algorithm will be used to select the texture index. If it’s 0 or larger, it will select the texture in the same order as the &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; lines in the &amp;lt;code&amp;gt;SignalTextures&amp;lt;/code&amp;gt;. Larger values than the number of states will be clamped to the last state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_setup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_setup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_setup(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ss: &amp;amp;amp;mut ShiftSetup&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when an unassigned train decides to lookup a new shift to run, it will first call &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The parameter &amp;lt;code&amp;gt;ss&amp;lt;/code&amp;gt; is both an input and output parameter. It is initialized with the current, relevant data for the given train state, and &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; can then change it, to influence which shifts will be considered by the shift selection algorithm. It can change the train position used for matching, the time used for matching, and disable the check for reservations. For matched shifts which do not correspond to the current train position, the Extrapolator system will automatically pathfind a temporary milestone for the train, like other path-changing features.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_allow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_allow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_allow(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    run: &amp;amp;amp;Run,&lt;br /&gt;
    stop_idx: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    pose: &amp;amp;amp;Pose&lt;br /&gt;
): ShiftAllow { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when the shift selection algorithm fins a valid shift for the given train, it will call &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; with all the relevant data. The return of the function can then allow or deny the shift. If the shift is denied, the algorithm will resume immediately, trying other shifts&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are independent from each other, and can be used in any combination.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;linestop-event_line_stop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Line::Stop event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestStop extend Line::Stop {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestStop::event_line_stop(&lt;br /&gt;
    self: &amp;amp;amp;TestStop,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == LineStopEvent::Arrive {&lt;br /&gt;
        log(&amp;amp;quot;@ arrives @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ departs @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given line stop in the line editor. From that moment, when any train arrives or departs said line stop, &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LineStopEvent::Depart&amp;lt;/code&amp;gt; to distinguish between arrival and departure. Waypoints are only called for &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt;. Shift-less trains are also called.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;shift-event_shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Shift event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestShift extend Shift {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestShift::event_shift(&lt;br /&gt;
    self: &amp;amp;amp;TestShift,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == ShiftEvent::Assign {&lt;br /&gt;
        log(&amp;amp;quot;@ assigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ unassigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given schedule shift in the line editor. From that moment, when any train is assigned to the shift, or becomes unassigned from the shift, &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;ShiftEvent::Assign&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ShiftEvent::Unassign&amp;lt;/code&amp;gt; to distinguish between assignation and unassignation. The &amp;lt;code&amp;gt;Assign&amp;lt;/code&amp;gt; event is called just after &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been set up, so it already has all the shift and run information. The &amp;lt;code&amp;gt;Unassign&amp;lt;/code&amp;gt; event is called just before &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been cleared of all shift and run information so the script has access to as much information as possible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;global-events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Global events ==&lt;br /&gt;
&lt;br /&gt;
Like event functions of struct extensions, global events are called as part of the core simulation engine when a specific event occurs, but they are not associated to any struct. Instead they are public top level functions with the signature given in this document. Global event functions are always called if they exist in a script and the event occurs.&lt;br /&gt;
&lt;br /&gt;
=== global_event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn global_event_line_stop(&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    log(&amp;amp;quot;global_event_line_stop: @ on line @&amp;amp;quot;, train, line);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Arguments and conditions are identical to &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt;, except there is no &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter.&lt;br /&gt;
&lt;br /&gt;
=== global_event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn global_event_shift(&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    log(&amp;amp;quot;global_event_shift: @ on sched @&amp;amp;quot;, train, sched);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Arguments and conditions are identical to &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt;, except there is no &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;controllers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Controllers ==&lt;br /&gt;
&lt;br /&gt;
Controller functions are called at a low frame rate compared to the overall simulation, with an (unchangeable) rate of once in 6 sim-seconds. They do not need any specific event or trigger to run, other than their enforced timer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-control_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train control_train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct HateDepots extend Train {}&lt;br /&gt;
pub fn HateDepots::control_train(&lt;br /&gt;
    self: &amp;amp;amp;HateDepots,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    // train is already removed from the tracks, don't interfere with potential attempts at shift assignation&lt;br /&gt;
    if !is_valid(motion.presence.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is running a schedule, don't interfere&lt;br /&gt;
    if is_valid(motion.schedule_dispatch.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is present, but it is not running a schedule, so despawn it&lt;br /&gt;
    sc.queue_train_intervention(train);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The train motion engine will call train controllers in the multithreaded phase, as part of the regular train motion extrapolator, after all the C++ code is done for a frame for a particular train, but before any queued commands are executed. Command execution will only happen after all train controllers for a given frame are done. In other words, train controllers queue up work to be executed by the sim. They never directly change the sim in any way, allowing train controller execution to be fully parallel.&lt;br /&gt;
&lt;br /&gt;
After all controllers are run, and all their non-task commands are executed, and then tasks are executed. Read more about tasks later on. Any tasks with a deadline which expired in this frame a run at this time too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontroller-command-queue&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== SimController command queue ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; object implements an API to control the simulation, including modification of some parameters and behaviors. It is also responsible for attaching and erasing private struct data from game objects, on behalf of scripts. The execution of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; is based on a command queue. Every call queues a command and returns immediately to the script code, without making any changes to the game state. Therefore the game state never changes while the script code is running.&lt;br /&gt;
&lt;br /&gt;
Commands queued from events and &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt; are executed asynchronously, there is no guaranteed order of execution! You must prepare your code and data for this design. For stand alone tasks scripts commands are executed in order and in isolation. You can queue up tasks from event and control scripts when you need to guarantee data consistency beyond “pick a random winner”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SimpleSimController&amp;lt;/code&amp;gt; is a cut down version of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; for high frequency events like &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt;. The reference in the second part of this document lists which &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; functions are available in &amp;lt;code&amp;gt;SimpleSimController&amp;lt;/code&amp;gt;, and they work identically.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_intervention&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_intervention ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks, releases its schedule shift (if any), and deletes and refunds its pax (if any). No other cost other than pax refunds is issued. This function can be used as a general “despawn the train” feature, not just for exceptional circumstances.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_warp&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_warp ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks and repositions it at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, re-pathing it to its currently scheduled destination (if any), and setting its speed to 0. This is basically a train wormhole. The train keeps its shift and pax, if any.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_drive_to&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_drive_to ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Re-paths the train path to end at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, without any changes to its shift or pax (if any). It is possible for any future &amp;lt;code&amp;gt;queue_train_drive_to&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; to reset this path at any point, losing the destination. “Queue” here is used as part of the SimController API semantics, it does not mean the train keeps a queue of positions to reach. If the path is not interrupted and the train reaches &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; it will re-path itself towards its current scheduled stop, if it has any, or brake to a stop if unassigned. If &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; was also in the stop area set for its current scheduled stop it will also brake to stop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_attach&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_attach ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the attachment of the &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;existing.clone()&amp;lt;/code&amp;gt;) to the &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt;, which must be of one of the following types: &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attached objects can be accessed with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt; at some point in the future. If called from a controller function, the attached object will be accessible after all controller functions are done for a given frame. If called from a task, he attached object will be accessible immediately after the task returns, and before any other task is executed. In other words, tasks are transaction-like, in the sense they view an immutable snapshot of the game state, and any changes they queue are executed before any other task, and then visible from these other tasks.&lt;br /&gt;
&lt;br /&gt;
Attaching an object of a given private struct type when it already exists attached to a &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt; will overwrite it. This is how private data is updated from scripting: by using &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; to copy any existing data, modifying the copy, then calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; to replace the existing data. Therefore it is a good idea to keep your private structs small. Only one instance of a given private struct type can be attached to any particular model object, but you can attach as many different private struct types as you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_erase&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_erase ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the erasure of &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt;, which must obtained using with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt;. Trying to erase temporary objects (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;existing.clone()&amp;lt;/code&amp;gt;) is ignored. The execution of the queued erase commands is analog to the &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; case. In particular a sequences of attach and erase queued from controllers will produce undefined results (impossible to predict which attach and/or erase wins). For example multiple attach from a controller for the same model_obj and private struct type will implicitly pick a singular “winner” attach, but the script does not have any control over which one. Sequences of attach and erase queued from tasks are strictly ordered and isolated, so they produce consistent results, in the same order they were queued in the task script, without any concurrent changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task-and-simcontrollerqueue_task_at&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task and SimController::queue_task_at ===&lt;br /&gt;
&lt;br /&gt;
See [[#Control%20tasks|control tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task_event_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task_event_train ===&lt;br /&gt;
&lt;br /&gt;
See [[#Event%20tasks|event tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;control-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Control tasks ==&lt;br /&gt;
&lt;br /&gt;
Control tasks are a very special kind of command which allows scripts to dynamically queue “future work”, with privileged access to the sim. Scripts with access to &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; can call this function to queue up a task for future script execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; must be of a private struct type which implements &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example { ... }&lt;br /&gt;
pub fn Example::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
For example, a train controller script could decide it needs to delay some decision into a task for data consistency reasons (other controllers are running at the same time), and delegate into a task rather than directly calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ControlTrain extend Train { ... }&lt;br /&gt;
pub fn ControlTrain::control_train(&lt;br /&gt;
    self: &amp;amp;amp;ControlTrain,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    task.train_id = train.id;&lt;br /&gt;
    task.v = some_data_from_somewhere;&lt;br /&gt;
    task.prio = 42; // or something smarter, like from ControlTrain, other objects, etc.&lt;br /&gt;
    sc.queue_task(task);&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
struct Task {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
struct SomeData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
pub fn Task::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    let train &amp;amp;amp;= ctx.db.view(self.train_id) else { return; }&lt;br /&gt;
    if let existing &amp;amp;amp;= ctx.db.view&amp;amp;lt;SomeData&amp;amp;gt;(train) {&lt;br /&gt;
        if existing.prio &amp;amp;gt;= self.prio {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    let data = SomeData::new();&lt;br /&gt;
    data.v = self.v;&lt;br /&gt;
    data.prio = self.prio;&lt;br /&gt;
    sc.queue_attach(train, data);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the previous example, maybe &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; will be called multiple times because multiple &amp;lt;code&amp;gt;ControlTrain::control_train()&amp;lt;/code&amp;gt; instances queued objects of &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;, but each execution will be single threaded, and all its queued &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; commands will be executed just after the call is done and before any other &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; call (for &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; or any other struct type), therefore the algorithm to pick a winner based on an explicit priority works.&lt;br /&gt;
&lt;br /&gt;
As mentioned, task execution is single threaded. The game does not feature a real concurrent database, instead all concurrent access is bespoke and very carefully designed to avoid deadlocks and inconsistencies (this is much faster than a general purpose concurrent database). Scripts also run in this parallel system, but their access to the game state is carefully restricted as explained earlier. But in the end, scripts also need to modify data, and do so in a consistent way. Tasks solve this issue, but do so in the most pessimistic possible way, by being single threaded. Therefore script developers should use them in moderation. Consider the “random winner” semantics of control script queuing first, which are completely free performance wise, before deciding you need a task. It is often the case a concurrent problem reduces to “pick 0 or 1 winners, any winner, but never 2 or more” and the default queue semantics already provide that guarantee for attaching a specific model/private pair.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; is provided with &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt;, therefore it can queue tasks itself. But unlike controller queuing tasks, which are guaranteed to run on the same frame, tasks queued from tasks are guaranteed to ''not'' run on the same frame, on purpose. They are deliberately stored away and forced a delay of 6 sim-seconds. This is to avoid misuse of tasks, and infinite looping.&lt;br /&gt;
&lt;br /&gt;
This behavior might even be desirable in certain scripts, for example if you are developing some stateful signal system and you need some kind of “cleanup” task that makes sure some signal being owned by some train is still the focus of said train. You can deliberately queue tasks for future simulation frames with &amp;lt;code&amp;gt;queue_task_at&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;deadline&amp;lt;/code&amp;gt; is expressed as microseconds since the start of the current save world. You can obtain the current simulation frame &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; value with &amp;lt;code&amp;gt;Extrapolator::clock_us()&amp;lt;/code&amp;gt;, like in this example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;    // schedule task to run 10 sim-s from now&lt;br /&gt;
    sc.queue_task_at(task, ctx.extrapolator.clock_us() + 10000000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;event-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Event tasks ==&lt;br /&gt;
&lt;br /&gt;
Event tasks are a lightweight version of tasks which run when triggered by certain events. Unlike control tasks, event tasks do not have unlimited access to the sim. Instead the run under an &amp;lt;code&amp;gt;EventCtx&amp;lt;/code&amp;gt; like pub struct events, and run multithreaded, at the same time as the C++ code. Unlike the regular &amp;lt;code&amp;gt;event_*&amp;lt;/code&amp;gt; methods, event tasks are queued for execution by script code, not by UI player commands. The design idea of these tasks is to offer a more focused and efficient execution model than &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt;: they are executed immediately once the relevant event happens, in multithreaded context, rather than require passive polling which might even miss certain events and force execution of single thread code.&lt;br /&gt;
&lt;br /&gt;
Any function with a &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; parameter can queue an even task like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Task {...}&lt;br /&gt;
fn f(..., train: &amp;amp;amp;Train, sc: &amp;amp;amp;mut SimController) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    sc.queue_task_event_train(task, train, TaskEventTrain::StopDepart);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
On the next stop departure of the train the &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt; method will be called:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn Task::task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: TaskEventTrain,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == TaskEventTrain::StopDepart {&lt;br /&gt;
        log(&amp;amp;quot;@ departs&amp;amp;quot;, train);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Like control tasks, event tasks encapsulate a single call. If a series of calls are desired, the task can requeue itself by calling &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt;. Event tasks are limited to a maximum of 1 for every possible train-struct-event combination, to avoid leaks. Trying to queue again the same train-struct-event combination will overwrite any existing task. Only the train and motion are provided as parameters. The code can then drill into motion to extract any required information, like shift or line.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-controlctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ControlCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ControlCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    sim: &amp;amp;amp;Sim,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim controller scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects, and associated script stuct objects.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::track_pos_project(self: &amp;amp;amp;DB, pos: &amp;amp;amp;Pos, distance: f64): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return a track position separated by ‘distance’ meters from ‘pos’, in the direction of ‘pos’. If distance is negative it will be in the opposite direction. Can only follow the main track. Merges and dead ends will return a Pos a shorter distance away. Signals are ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view_self(self: &amp;amp;amp;DB): &amp;amp;amp;Script&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-eventctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type EventCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct EventCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim event handler scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line::Stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line::Stop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    cars_config: i32,&lt;br /&gt;
    dynamics: Train::Dynamics,&lt;br /&gt;
    hitched_by: Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    station_stop: std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;,&lt;br /&gt;
    run_stop: std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
    run_dispatch: std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;,&lt;br /&gt;
    hitch: std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motioncachedhitcher&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::CachedHitcher ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::CachedHitcher {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionhitch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Hitch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Hitch {&lt;br /&gt;
    driver_train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    flip: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Train is being hitched by a driver train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
    flip: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionrundispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::RunDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::RunDispatch {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a line run.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Motion::RunDispatch::current_stop(self: &amp;amp;amp;Motion::RunDispatch, line: &amp;amp;amp;Line): *Line::Stop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionstationstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::StationStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::StationStop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Schedule::view(self: &amp;amp;amp;Schedule, shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;): *Shift&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns a pointer to the shift, if it’s contained in this schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-script&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Script ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Script {&lt;br /&gt;
    id: ID&amp;amp;lt;Script&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Shift {&lt;br /&gt;
    id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::kind(self: &amp;amp;amp;Signal): mut SignalKind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the signal kind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Track::max_speed(self: &amp;amp;amp;Track): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the min(physical, manual setting) max speed of the track, in m/s.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
    as_purchased: Train::Dynamics,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-traindynamics&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train::Dynamics ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train::Dynamics {&lt;br /&gt;
    max_speed: f32,&lt;br /&gt;
    max_acceleration: f32,&lt;br /&gt;
    max_regular_braking: f32,&lt;br /&gt;
    max_emergency_braking: f32,&lt;br /&gt;
    max_tractive_effort: f32,&lt;br /&gt;
    total_power: f32,&lt;br /&gt;
    empty_mass: f32,&lt;br /&gt;
    length: f32,&lt;br /&gt;
    max_pax: i32,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vec&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;lt;Motion::CachedHitcher&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Hitch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;): *Motion::Hitch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStationEvent&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;&lt;br /&gt;
): *Motion::StationStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Script&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Shift&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Shift&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Shift&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciterator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;lt;Motion::CachedHitcher&amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator::next(&lt;br /&gt;
    self: &amp;amp;amp;mut Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator&lt;br /&gt;
): *Motion::CachedHitcher&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    idx: i64&lt;br /&gt;
): *Motion::CachedHitcher&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::clock_us(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current microseconds since the creation of this saved game. This is used as the timing root of the simulation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second since 1970-01-01:00:00:00.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_occupation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_reservation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying or reserving the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_occupying(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_reserving(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying or reserving the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
Probe a track position for train reservations and occupations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::view_last&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Extrapolator, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the last frame Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Seconds since 1970-01-01:00:00:00 for Monday 00:00:00 of the current week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestopevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type LineStopEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum LineStopEvent {&lt;br /&gt;
    Arrive,&lt;br /&gt;
    Depart,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
Advance the iterator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftallow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftAllow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftAllow {&lt;br /&gt;
    Allow,&lt;br /&gt;
    Deny,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftEvent {&lt;br /&gt;
    Assign,&lt;br /&gt;
    Unassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftsetup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftSetup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ShiftSetup {&lt;br /&gt;
    skip: bool,&lt;br /&gt;
    match_pos: bool,&lt;br /&gt;
    check_occupation: bool,&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores the context of a train shift lookup.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function wants to change the train path, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signallookaheadresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalLookaheadResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalLookaheadResult {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores extra information associated with the result of the signal lookahead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-sim&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Sim ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Sim {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of the simulation state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Sim::view&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Sim, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A proxy mutable API to the simulation engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    ev: TaskEventTrain&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_hitch(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    driver: &amp;amp;amp;Train,&lt;br /&gt;
    hitcher: &amp;amp;amp;Train,&lt;br /&gt;
    order: i64,&lt;br /&gt;
    flip: bool&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hitch a train to a driver train. The hitched train is emptied of pax and removed from the sim, while its cars are appended to the driver. The order parameter (from -1000 to 1000) determines the hitched train cars position: the driver train is always order 0, so negative values will put the hitch in front of the driver, and positive values behind it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(self: &amp;amp;amp;mut SimController, train: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_run_line(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    arrival_offset_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_configuration(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    config: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_presence_flip(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    flip: bool&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_stop_delay(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    delay_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add extra delay time to a stopped train that has a timed_stop component.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_unhitch(self: &amp;amp;amp;mut SimController, hitcher: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Remove the hitched state from a train. It will become an unspawned, unassigned train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simplesimcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimpleSimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimpleSimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A limited API version of SimController.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimpleSimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimpleSimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-taskeventtrain&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TaskEventTrain ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum TaskEventTrain {&lt;br /&gt;
    StopArrive,&lt;br /&gt;
    StopDepart,&lt;br /&gt;
    ShiftAssign,&lt;br /&gt;
    ShiftUnassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=560</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=560"/>
		<updated>2026-01-30T12:45:02Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used in game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration, integer division or arbitrary setting of pointers and references, and most data exposed to scripts is read-only, strictly enforced by the language. Any expression result which could result in an out of bounds or invalid memory access must be checked for validity, and the API design together with the type system enforces it.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
pub struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;SpeedTrap,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- VisMod? 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' ColonNAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Script&amp;lt;/code&amp;gt; (with restrictions)&lt;br /&gt;
&lt;br /&gt;
Structs extending game types for player extensions must be declared as &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt;. When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
To read struct objects from script code they must be looked up using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API. Therefore only functions provided with &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt; object (or a context object with contains &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt;) can look up these objects. But you can pass around &amp;lt;code&amp;gt;DB&amp;amp;amp;&amp;lt;/code&amp;gt; as a parameter without any lifetime restrictions, since it’s a purely read only API. This API also works for non-pub structs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= ctx.db.view&amp;amp;lt;Example&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    log(&amp;amp;quot;v = @&amp;amp;quot;, config.v);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;pub-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== pub structs ====&lt;br /&gt;
&lt;br /&gt;
As explained earlier, &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs are the user interface of your scripts. They are exposed in the UI as input forms, and their &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;s can give some control over this rendering. Conceptually they are owned by the player of the game as part of the game object database, by attaching them to a game model object in the database, not the script. Scripts do not have any capability to create, edit or delete objects of &amp;lt;code&amp;gt;pub struct&amp;lt;/code&amp;gt;s. It is always the player who decides when to create a new object of these structs by interacting in the UI. Scripts can then read, and only read, the content of these objects, by using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API presented earlier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs have a very powerful capability: they have limited support for forward schema evolution. This means that the script developer can add to, and reorder, fields in &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, and the game runtime will be able keep the contents of the other fields intact. This is very important to respect the input data by the player. If you rename &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs or their fields, or change their types, the player input data will be lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;non-pub-or-private-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Non-pub (or private) structs ====&lt;br /&gt;
&lt;br /&gt;
Non-&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, also called private structs, are conceptually owned by the script as a part of the simulation, not the player. Their contents are assumed to be a black box by the rest of the game. Scripts are allowed to create and modify objects of these structs during their execution, which are automatically deleted at the end of the simulation frame. It is also possible to attach these structs to existing game model objects to extend their lifetime beyond the current frame. In this case their lifetime becomes the same as the game object, and they can be retrieved in later frames for reading, deleted or overwritten as desired.&lt;br /&gt;
&lt;br /&gt;
Private structs ''do not support schema evolution''. Changing field types, field names, reordering of fields, even just adding new fields at the end, will always result in losing all existing attached objects of the given struct. Some operations like resetting the simulation will also erase attached objects, because they are considered simulation state, not player created objects.&lt;br /&gt;
&lt;br /&gt;
Private structs support dynamic memory allocation. All private struct definitions automatically create a &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; method for the struct:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct PrivData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let ro &amp;amp;amp;= ctx.db.view&amp;amp;lt;PrivData&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    let rw &amp;amp;amp;mut= ro.clone();&lt;br /&gt;
    rw.v = 100;&lt;br /&gt;
    let empty &amp;amp;amp;mut= PrivData::new();&lt;br /&gt;
    empty.v = 200;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The objects allocated by &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; are always deleted at the end of the current simulation frame. Their lifetime can be extended beyond the current frame by attaching them to a game object, like &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, so their lifetime becomes the same as the attached object. The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API has methods for attaching and erasing these object.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;host-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Host structs ====&lt;br /&gt;
&lt;br /&gt;
Many of the exposed game APIs are also based around structs. These structs do not follow any of the previous rules. Some have special capabilities, for example simple structs like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt; are ''value objects'': they can be copied and passed around like any &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; would. Some others are strictly locked down and serve as very little beyond a way to keep a pointer safe. In general, when working with game API structs, assume they are what would be called ''move only'' in C++. And NimbyScript has no move operator or semantics, so in essence assume they are immutable, immobile references, except when documented otherwise (like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As an aside, all script declared &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; or not) are also always ''move only'', and always “owned” by some external entity. This is why the APIs for their manipulation are always based on pointers and references, even for private structs. It is not possible to create plain, stack allocated values of script structs, or to use them as fields in structs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version:&lt;br /&gt;
&lt;br /&gt;
* Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
* Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums)&lt;br /&gt;
* For pub structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* For private structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In pub structs these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types. &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; will also display a small list editor. Keep in mind the correct type is &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;Vec&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- 'let' BindBody 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- 'let' BindBody ';'&lt;br /&gt;
BindBody    &amp;amp;lt;- NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' 'let' BindBody BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- ColonNAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere pointer types cannot be dereferenced, therefore cannot be used in dot expressions. The exception is the built-in function &amp;lt;code&amp;gt;is_valid(ptr): bool&amp;lt;/code&amp;gt;, which is usable with any pointer type.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;extensions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Extensions =&lt;br /&gt;
&lt;br /&gt;
Extending game database struct data with &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt; can also be used to extend the game code. The mechanism to do so is to first declare a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;ing a game database object (with or without fields). Then create a specifically named and parametrized function which will be called by the game under certain situations, for certain kinds of objects.&lt;br /&gt;
&lt;br /&gt;
All extension functions take a &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter which is a reference to the struct which it is method of, called &amp;lt;code&amp;gt;Example&amp;lt;/code&amp;gt; in the following sections. Replace it with your struct name. The rest of the parameters are fixed and must be reproduced exactly as-is.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
Event functions are called as part of the core simulation engine. They are meant to be focused in features and quick to execute. These functions might be called thousands of times per simulation frame, including multiple redundant times. Their capability to change the simulation behavior is usually very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_check&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_check ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails, or if another script call returns &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_lookahead&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_lookahead ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_lookahead(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    train_distance: f64,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalLookaheadResult&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; function at regular intervals for each signal 15km ahead of the train path. It is called for all signals, until one of these conditions hold:&lt;br /&gt;
&lt;br /&gt;
* One of the signals path checks as &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;&lt;br /&gt;
* Another train is found&lt;br /&gt;
* The train stop is found&lt;br /&gt;
* 15km have been checked&lt;br /&gt;
&lt;br /&gt;
For both &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; signals, your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; will be called, and you can check the path find result in &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;, and the distance from the train in &amp;lt;code&amp;gt;train_distance&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; allows to set a maximum speed for the train, which goes into effect immediately. This works from any distance and past any amount of signals between the train and the caller signal. If multiple signals in the lookahead path return a &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt;, the slowest speed is picked. If no &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt; is set, or it is 0, the result is ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; default value is 0, which is considered invalid and will be ignored. To stop the train at the signal implement &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_change_path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_change_path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_change_path(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The current path check result of this signal for the passed train is passed as &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;. This already includes any results from &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_pass_by&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_pass_by ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_pass_by(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; function on the exact simulation frame a train passes by the exact point of the signal on the track.&lt;br /&gt;
&lt;br /&gt;
This function has no return result. Instead, since it has a predictably low call rate compared to the other events, it is the only event function with access to the powerful &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_marker_reserved&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_marker_reserved ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given marker signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; any time the reservation check algorithm is tracing a path which goes over the marker signal, on any direction, giving it the chance to report an arbitrary train as the reserver of that point on the track.&lt;br /&gt;
&lt;br /&gt;
This signal has a potential huge call rate, and for this reason it is given very little access to the APIs. The intention is that all the state required by this signal is calculated somewhere else and attached to the signal as a private struct object, or to some object reachable from it. Don’t worry about filtering for the “same train” cases, this is automatically done.&lt;br /&gt;
&lt;br /&gt;
If no reservation is desired, use the &amp;lt;code&amp;gt;empty&amp;lt;/code&amp;gt; global method available in all &amp;lt;code&amp;gt;ID&amp;amp;lt;Class&amp;amp;gt;&amp;lt;/code&amp;gt; types: &amp;lt;code&amp;gt;return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {}&lt;br /&gt;
struct Owner {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; {&lt;br /&gt;
    // some other, more full featured script function has attached Owner to this signal,&lt;br /&gt;
    // or not, so we need to check first&lt;br /&gt;
    if let owner &amp;amp;amp;= db.view&amp;amp;lt;Owner&amp;amp;gt;(signal) {&lt;br /&gt;
        if is_valid(db.view(owner.train_id)) {&lt;br /&gt;
            return owner.train_id;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_texture_state&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_texture_state ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_texture_state(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    clock_us: i64&lt;br /&gt;
): i64 { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment, when the game UI needs to query what is the current signal texture state index, it will call your &amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt;, with some potential caching to keep the call rate lower. In any case the call rate of this function is potentially very large when the user zooms out the map, so make sure to keep its code as efficient as possible. For this same reason it is given very little access to the APIs. &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; is the number of sim-microseconds since the current save was created, you use it with the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; functions to make animations.&lt;br /&gt;
&lt;br /&gt;
The return value indicates which signal texture state is to be used. If it’s -1 or lower, the default algorithm will be used to select the texture index. If it’s 0 or larger, it will select the texture in the same order as the &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; lines in the &amp;lt;code&amp;gt;SignalTextures&amp;lt;/code&amp;gt;. Larger values than the number of states will be clamped to the last state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_setup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_setup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_setup(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ss: &amp;amp;amp;mut ShiftSetup&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when an unassigned train decides to lookup a new shift to run, it will first call &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The parameter &amp;lt;code&amp;gt;ss&amp;lt;/code&amp;gt; is both an input and output parameter. It is initialized with the current, relevant data for the given train state, and &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; can then change it, to influence which shifts will be considered by the shift selection algorithm. It can change the train position used for matching, the time used for matching, and disable the check for reservations. For matched shifts which do not correspond to the current train position, the Extrapolator system will automatically pathfind a temporary milestone for the train, like other path-changing features.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_allow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_allow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_allow(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    run: &amp;amp;amp;Run,&lt;br /&gt;
    stop_idx: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    pose: &amp;amp;amp;Pose&lt;br /&gt;
): ShiftAllow { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when the shift selection algorithm fins a valid shift for the given train, it will call &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; with all the relevant data. The return of the function can then allow or deny the shift. If the shift is denied, the algorithm will resume immediately, trying other shifts&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are independent from each other, and can be used in any combination.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;linestop-event_line_stop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Line::Stop event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestStop extend Line::Stop {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestStop::event_line_stop(&lt;br /&gt;
    self: &amp;amp;amp;TestStop,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == LineStopEvent::Arrive {&lt;br /&gt;
        log(&amp;amp;quot;@ arrives @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ departs @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given line stop in the line editor. From that moment, when any train arrives or departs said line stop, &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LineStopEvent::Depart&amp;lt;/code&amp;gt; to distinguish between arrival and departure. Waypoints are only called for &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt;. Shift-less trains are also called.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;shift-event_shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Shift event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestShift extend Shift {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestShift::event_shift(&lt;br /&gt;
    self: &amp;amp;amp;TestShift,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == ShiftEvent::Assign {&lt;br /&gt;
        log(&amp;amp;quot;@ assigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ unassigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given schedule shift in the line editor. From that moment, when any train is assigned to the shift, or becomes unassigned from the shift, &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;ShiftEvent::Assign&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ShiftEvent::Unassign&amp;lt;/code&amp;gt; to distinguish between assignation and unassignation. The &amp;lt;code&amp;gt;Assign&amp;lt;/code&amp;gt; event is called just after &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been set up, so it already has all the shift and run information. The &amp;lt;code&amp;gt;Unassign&amp;lt;/code&amp;gt; event is called just before &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been cleared of all shift and run information so the script has access to as much information as possible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;global-events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Global events ==&lt;br /&gt;
&lt;br /&gt;
Like event functions of struct extensions, global events are called as part of the core simulation engine when a specific event occurs, but they are not associated to any struct. Instead they are public top level functions with the signature given in this document. Global event functions are always called if they exist in a script and the event occurs.&lt;br /&gt;
&lt;br /&gt;
=== global_event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn global_event_line_stop(&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    log(&amp;amp;quot;global_event_line_stop: @ on line @&amp;amp;quot;, train, line);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Arguments and conditions are identical to &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt;, except there is no &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter.&lt;br /&gt;
&lt;br /&gt;
=== global_event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn global_event_shift(&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    log(&amp;amp;quot;global_event_shift: @ on sched @&amp;amp;quot;, train, sched);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Arguments and conditions are identical to &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt;, except there is no &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;controllers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Controllers ==&lt;br /&gt;
&lt;br /&gt;
Controller functions are called at a low frame rate compared to the overall simulation, with an (unchangeable) rate of once in 6 sim-seconds. They do not need any specific event or trigger to run, other than their enforced timer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-control_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train control_train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct HateDepots extend Train {}&lt;br /&gt;
pub fn HateDepots::control_train(&lt;br /&gt;
    self: &amp;amp;amp;HateDepots,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    // train is already removed from the tracks, don't interfere with potential attempts at shift assignation&lt;br /&gt;
    if !is_valid(motion.presence.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is running a schedule, don't interfere&lt;br /&gt;
    if is_valid(motion.schedule_dispatch.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is present, but it is not running a schedule, so despawn it&lt;br /&gt;
    sc.queue_train_intervention(train);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The train motion engine will call train controllers in the multithreaded phase, as part of the regular train motion extrapolator, after all the C++ code is done for a frame for a particular train, but before any queued commands are executed. Command execution will only happen after all train controllers for a given frame are done. In other words, train controllers queue up work to be executed by the sim. They never directly change the sim in any way, allowing train controller execution to be fully parallel.&lt;br /&gt;
&lt;br /&gt;
After all controllers are run, and all their non-task commands are executed, and then tasks are executed. Read more about tasks later on. Any tasks with a deadline which expired in this frame a run at this time too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontroller-command-queue&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== SimController command queue ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; object implements an API to control the simulation, including modification of some parameters and behaviors. It is also responsible for attaching and erasing private struct data from game objects, on behalf of scripts. The execution of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; is based on a command queue. Every call queues a command and returns immediately to the script code, without making any changes to the game state. Therefore the game state never changes while the script code is running.&lt;br /&gt;
&lt;br /&gt;
Commands queued from events and &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt; are executed asynchronously, there is no guaranteed order of execution! You must prepare your code and data for this design. For stand alone tasks scripts commands are executed in order and in isolation. You can queue up tasks from event and control scripts when you need to guarantee data consistency beyond “pick a random winner”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SimpleSimController&amp;lt;/code&amp;gt; is a cut down version of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; for high frequency events like &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt;. The reference in the second part of this document lists which &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; functions are available in &amp;lt;code&amp;gt;SimpleSimController&amp;lt;/code&amp;gt;, and they work identically.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_intervention&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_intervention ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks, releases its schedule shift (if any), and deletes and refunds its pax (if any). No other cost other than pax refunds is issued. This function can be used as a general “despawn the train” feature, not just for exceptional circumstances.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_warp&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_warp ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks and repositions it at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, re-pathing it to its currently scheduled destination (if any), and setting its speed to 0. This is basically a train wormhole. The train keeps its shift and pax, if any.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_drive_to&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_drive_to ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Re-paths the train path to end at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, without any changes to its shift or pax (if any). It is possible for any future &amp;lt;code&amp;gt;queue_train_drive_to&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; to reset this path at any point, losing the destination. “Queue” here is used as part of the SimController API semantics, it does not mean the train keeps a queue of positions to reach. If the path is not interrupted and the train reaches &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; it will re-path itself towards its current scheduled stop, if it has any, or brake to a stop if unassigned. If &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; was also in the stop area set for its current scheduled stop it will also brake to stop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_attach&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_attach ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the attachment of the &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;existing.clone()&amp;lt;/code&amp;gt;) to the &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt;, which must be of one of the following types: &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attached objects can be accessed with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt; at some point in the future. If called from a controller function, the attached object will be accessible after all controller functions are done for a given frame. If called from a task, he attached object will be accessible immediately after the task returns, and before any other task is executed. In other words, tasks are transaction-like, in the sense they view an immutable snapshot of the game state, and any changes they queue are executed before any other task, and then visible from these other tasks.&lt;br /&gt;
&lt;br /&gt;
Attaching an object of a given private struct type when it already exists attached to a &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt; will overwrite it. This is how private data is updated from scripting: by using &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; to copy any existing data, modifying the copy, then calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; to replace the existing data. Therefore it is a good idea to keep your private structs small. Only one instance of a given private struct type can be attached to any particular model object, but you can attach as many different private struct types as you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_erase&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_erase ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the erasure of &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt;, which must obtained using with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt;. Trying to erase temporary objects (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;existing.clone()&amp;lt;/code&amp;gt;) is ignored. The execution of the queued erase commands is analog to the &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; case. In particular a sequences of attach and erase queued from controllers will produce undefined results (impossible to predict which attach and/or erase wins). For example multiple attach from a controller for the same model_obj and private struct type will implicitly pick a singular “winner” attach, but the script does not have any control over which one. Sequences of attach and erase queued from tasks are strictly ordered and isolated, so they produce consistent results, in the same order they were queued in the task script, without any concurrent changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task-and-simcontrollerqueue_task_at&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task and SimController::queue_task_at ===&lt;br /&gt;
&lt;br /&gt;
See [[#Control%20tasks|control tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task_event_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task_event_train ===&lt;br /&gt;
&lt;br /&gt;
See [[#Event%20tasks|event tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;control-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Control tasks ==&lt;br /&gt;
&lt;br /&gt;
Control tasks are a very special kind of command which allows scripts to dynamically queue “future work”, with privileged access to the sim. Scripts with access to &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; can call this function to queue up a task for future script execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; must be of a private struct type which implements &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example { ... }&lt;br /&gt;
pub fn Example::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
For example, a train controller script could decide it needs to delay some decision into a task for data consistency reasons (other controllers are running at the same time), and delegate into a task rather than directly calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ControlTrain extend Train { ... }&lt;br /&gt;
pub fn ControlTrain::control_train(&lt;br /&gt;
    self: &amp;amp;amp;ControlTrain,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    task.train_id = train.id;&lt;br /&gt;
    task.v = some_data_from_somewhere;&lt;br /&gt;
    task.prio = 42; // or something smarter, like from ControlTrain, other objects, etc.&lt;br /&gt;
    sc.queue_task(task);&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
struct Task {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
struct SomeData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
pub fn Task::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    let train &amp;amp;amp;= ctx.db.view(self.train_id) else { return; }&lt;br /&gt;
    if let existing &amp;amp;amp;= ctx.db.view&amp;amp;lt;SomeData&amp;amp;gt;(train) {&lt;br /&gt;
        if existing.prio &amp;amp;gt;= self.prio {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    let data = SomeData::new();&lt;br /&gt;
    data.v = self.v;&lt;br /&gt;
    data.prio = self.prio;&lt;br /&gt;
    sc.queue_attach(train, data);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the previous example, maybe &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; will be called multiple times because multiple &amp;lt;code&amp;gt;ControlTrain::control_train()&amp;lt;/code&amp;gt; instances queued objects of &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;, but each execution will be single threaded, and all its queued &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; commands will be executed just after the call is done and before any other &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; call (for &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; or any other struct type), therefore the algorithm to pick a winner based on an explicit priority works.&lt;br /&gt;
&lt;br /&gt;
As mentioned, task execution is single threaded. The game does not feature a real concurrent database, instead all concurrent access is bespoke and very carefully designed to avoid deadlocks and inconsistencies (this is much faster than a general purpose concurrent database). Scripts also run in this parallel system, but their access to the game state is carefully restricted as explained earlier. But in the end, scripts also need to modify data, and do so in a consistent way. Tasks solve this issue, but do so in the most pessimistic possible way, by being single threaded. Therefore script developers should use them in moderation. Consider the “random winner” semantics of control script queuing first, which are completely free performance wise, before deciding you need a task. It is often the case a concurrent problem reduces to “pick 0 or 1 winners, any winner, but never 2 or more” and the default queue semantics already provide that guarantee for attaching a specific model/private pair.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; is provided with &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt;, therefore it can queue tasks itself. But unlike controller queuing tasks, which are guaranteed to run on the same frame, tasks queued from tasks are guaranteed to ''not'' run on the same frame, on purpose. They are deliberately stored away and forced a delay of 6 sim-seconds. This is to avoid misuse of tasks, and infinite looping.&lt;br /&gt;
&lt;br /&gt;
This behavior might even be desirable in certain scripts, for example if you are developing some stateful signal system and you need some kind of “cleanup” task that makes sure some signal being owned by some train is still the focus of said train. You can deliberately queue tasks for future simulation frames with &amp;lt;code&amp;gt;queue_task_at&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;deadline&amp;lt;/code&amp;gt; is expressed as microseconds since the start of the current save world. You can obtain the current simulation frame &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; value with &amp;lt;code&amp;gt;Extrapolator::clock_us()&amp;lt;/code&amp;gt;, like in this example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;    // schedule task to run 10 sim-s from now&lt;br /&gt;
    sc.queue_task_at(task, ctx.extrapolator.clock_us() + 10000000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;event-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Event tasks ==&lt;br /&gt;
&lt;br /&gt;
Event tasks are a lightweight version of tasks which run when triggered by certain events. Unlike control tasks, event tasks do not have unlimited access to the sim. Instead the run under an &amp;lt;code&amp;gt;EventCtx&amp;lt;/code&amp;gt; like pub struct events, and run multithreaded, at the same time as the C++ code. Unlike the regular &amp;lt;code&amp;gt;event_*&amp;lt;/code&amp;gt; methods, event tasks are queued for execution by script code, not by UI player commands. The design idea of these tasks is to offer a more focused and efficient execution model than &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt;: they are executed immediately once the relevant event happens, in multithreaded context, rather than require passive polling which might even miss certain events and force execution of single thread code.&lt;br /&gt;
&lt;br /&gt;
Any function with a &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; parameter can queue an even task like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Task {...}&lt;br /&gt;
fn f(..., train: &amp;amp;amp;Train, sc: &amp;amp;amp;mut SimController) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    sc.queue_task_event_train(task, train, TaskEventTrain::StopDepart);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
On the next stop departure of the train the &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt; method will be called:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn Task::task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: TaskEventTrain,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == TaskEventTrain::StopDepart {&lt;br /&gt;
        log(&amp;amp;quot;@ departs&amp;amp;quot;, train);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Like control tasks, event tasks encapsulate a single call. If a series of calls are desired, the task can requeue itself by calling &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt;. Event tasks are limited to a maximum of 1 for every possible train-struct-event combination, to avoid leaks. Trying to queue again the same train-struct-event combination will overwrite any existing task. Only the train and motion are provided as parameters. The code can then drill into motion to extract any required information, like shift or line.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-controlctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ControlCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ControlCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    sim: &amp;amp;amp;Sim,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim controller scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects, and associated script stuct objects.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::track_pos_project(self: &amp;amp;amp;DB, pos: &amp;amp;amp;Pos, distance: f64): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return a track position separated by ‘distance’ meters from ‘pos’, in the direction of ‘pos’. If distance is negative it will be in the opposite direction. Can only follow the main track. Merges and dead ends will return a Pos a shorter distance away. Signals are ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view_self(self: &amp;amp;amp;DB): &amp;amp;amp;Script&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-eventctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type EventCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct EventCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim event handler scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line::Stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line::Stop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    cars_config: i32,&lt;br /&gt;
    dynamics: Train::Dynamics,&lt;br /&gt;
    hitched_by: Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    station_stop: std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;,&lt;br /&gt;
    run_stop: std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
    run_dispatch: std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;,&lt;br /&gt;
    hitch: std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motioncachedhitcher&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::CachedHitcher ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::CachedHitcher {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionhitch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Hitch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Hitch {&lt;br /&gt;
    driver_train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    flip: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Train is being hitched by a driver train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
    flip: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionrundispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::RunDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::RunDispatch {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a line run.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Motion::RunDispatch::current_stop(self: &amp;amp;amp;Motion::RunDispatch, line: &amp;amp;amp;Line): *Line::Stop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionstationstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::StationStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::StationStop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Schedule::view(self: &amp;amp;amp;Schedule, shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;): *Shift&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns a pointer to the shift, if it’s contained in this schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-script&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Script ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Script {&lt;br /&gt;
    id: ID&amp;amp;lt;Script&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Shift {&lt;br /&gt;
    id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::kind(self: &amp;amp;amp;Signal): mut SignalKind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the signal kind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Track::max_speed(self: &amp;amp;amp;Track): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the min(physical, manual setting) max speed of the track, in m/s.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
    as_purchased: Train::Dynamics,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-traindynamics&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train::Dynamics ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train::Dynamics {&lt;br /&gt;
    max_speed: f32,&lt;br /&gt;
    max_acceleration: f32,&lt;br /&gt;
    max_regular_braking: f32,&lt;br /&gt;
    max_emergency_braking: f32,&lt;br /&gt;
    max_tractive_effort: f32,&lt;br /&gt;
    total_power: f32,&lt;br /&gt;
    empty_mass: f32,&lt;br /&gt;
    length: f32,&lt;br /&gt;
    max_pax: i32,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vec&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;lt;Motion::CachedHitcher&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Hitch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;): *Motion::Hitch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStationEvent&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;&lt;br /&gt;
): *Motion::StationStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Script&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Shift&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Shift&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Shift&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciterator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;lt;Motion::CachedHitcher&amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator::next(&lt;br /&gt;
    self: &amp;amp;amp;mut Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator&lt;br /&gt;
): *Motion::CachedHitcher&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    idx: i64&lt;br /&gt;
): *Motion::CachedHitcher&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::clock_us(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current microseconds since the creation of this saved game. This is used as the timing root of the simulation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second since 1970-01-01:00:00:00.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_occupation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_reservation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying or reserving the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_occupying(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_reserving(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying or reserving the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
Probe a track position for train reservations and occupations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Seconds since 1970-01-01:00:00:00 for Monday 00:00:00 of the current week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestopevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type LineStopEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum LineStopEvent {&lt;br /&gt;
    Arrive,&lt;br /&gt;
    Depart,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
Advance the iterator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftallow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftAllow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftAllow {&lt;br /&gt;
    Allow,&lt;br /&gt;
    Deny,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftEvent {&lt;br /&gt;
    Assign,&lt;br /&gt;
    Unassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftsetup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftSetup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ShiftSetup {&lt;br /&gt;
    skip: bool,&lt;br /&gt;
    match_pos: bool,&lt;br /&gt;
    check_occupation: bool,&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores the context of a train shift lookup.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function wants to change the train path, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signallookaheadresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalLookaheadResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalLookaheadResult {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores extra information associated with the result of the signal lookahead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-sim&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Sim ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Sim {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of the simulation state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Sim::view&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Sim, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A proxy mutable API to the simulation engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    ev: TaskEventTrain&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_hitch(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    driver: &amp;amp;amp;Train,&lt;br /&gt;
    hitcher: &amp;amp;amp;Train,&lt;br /&gt;
    order: i64,&lt;br /&gt;
    flip: bool&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hitch a train to a driver train. The hitched train is emptied of pax and removed from the sim, while its cars are appended to the driver. The order parameter (from -1000 to 1000) determines the hitched train cars position: the driver train is always order 0, so negative values will put the hitch in front of the driver, and positive values behind it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(self: &amp;amp;amp;mut SimController, train: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_run_line(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    arrival_offset_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_configuration(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    config: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_presence_flip(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    flip: bool&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_stop_delay(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    delay_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add extra delay time to a stopped train that has a timed_stop component.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_unhitch(self: &amp;amp;amp;mut SimController, hitcher: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Remove the hitched state from a train. It will become an unspawned, unassigned train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simplesimcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimpleSimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimpleSimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A limited API version of SimController.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimpleSimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimpleSimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-taskeventtrain&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TaskEventTrain ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum TaskEventTrain {&lt;br /&gt;
    StopArrive,&lt;br /&gt;
    StopDepart,&lt;br /&gt;
    ShiftAssign,&lt;br /&gt;
    ShiftUnassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=559</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=559"/>
		<updated>2026-01-25T16:56:01Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used in game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration, integer division or arbitrary setting of pointers and references, and most data exposed to scripts is read-only, strictly enforced by the language. Any expression result which could result in an out of bounds or invalid memory access must be checked for validity, and the API design together with the type system enforces it.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
pub struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;SpeedTrap,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- VisMod? 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' ColonNAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Script&amp;lt;/code&amp;gt; (with restrictions)&lt;br /&gt;
&lt;br /&gt;
Structs extending game types for player extensions must be declared as &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt;. When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
To read struct objects from script code they must be looked up using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API. Therefore only functions provided with &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt; object (or a context object with contains &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt;) can look up these objects. But you can pass around &amp;lt;code&amp;gt;DB&amp;amp;amp;&amp;lt;/code&amp;gt; as a parameter without any lifetime restrictions, since it’s a purely read only API. This API also works for non-pub structs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= ctx.db.view&amp;amp;lt;Example&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    log(&amp;amp;quot;v = @&amp;amp;quot;, config.v);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;pub-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== pub structs ====&lt;br /&gt;
&lt;br /&gt;
As explained earlier, &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs are the user interface of your scripts. They are exposed in the UI as input forms, and their &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;s can give some control over this rendering. Conceptually they are owned by the player of the game as part of the game object database, by attaching them to a game model object in the database, not the script. Scripts do not have any capability to create, edit or delete objects of &amp;lt;code&amp;gt;pub struct&amp;lt;/code&amp;gt;s. It is always the player who decides when to create a new object of these structs by interacting in the UI. Scripts can then read, and only read, the content of these objects, by using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API presented earlier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs have a very powerful capability: they have limited support for forward schema evolution. This means that the script developer can add to, and reorder, fields in &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, and the game runtime will be able keep the contents of the other fields intact. This is very important to respect the input data by the player. If you rename &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs or their fields, or change their types, the player input data will be lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;non-pub-or-private-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Non-pub (or private) structs ====&lt;br /&gt;
&lt;br /&gt;
Non-&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, also called private structs, are conceptually owned by the script as a part of the simulation, not the player. Their contents are assumed to be a black box by the rest of the game. Scripts are allowed to create and modify objects of these structs during their execution, which are automatically deleted at the end of the simulation frame. It is also possible to attach these structs to existing game model objects to extend their lifetime beyond the current frame. In this case their lifetime becomes the same as the game object, and they can be retrieved in later frames for reading, deleted or overwritten as desired.&lt;br /&gt;
&lt;br /&gt;
Private structs ''do not support schema evolution''. Changing field types, field names, reordering of fields, even just adding new fields at the end, will always result in losing all existing attached objects of the given struct. Some operations like resetting the simulation will also erase attached objects, because they are considered simulation state, not player created objects.&lt;br /&gt;
&lt;br /&gt;
Private structs support dynamic memory allocation. All private struct definitions automatically create a &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; method for the struct:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct PrivData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let ro &amp;amp;amp;= ctx.db.view&amp;amp;lt;PrivData&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    let rw &amp;amp;amp;mut= ro.clone();&lt;br /&gt;
    rw.v = 100;&lt;br /&gt;
    let empty &amp;amp;amp;mut= PrivData::new();&lt;br /&gt;
    empty.v = 200;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The objects allocated by &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; are always deleted at the end of the current simulation frame. Their lifetime can be extended beyond the current frame by attaching them to a game object, like &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, so their lifetime becomes the same as the attached object. The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API has methods for attaching and erasing these object.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;host-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Host structs ====&lt;br /&gt;
&lt;br /&gt;
Many of the exposed game APIs are also based around structs. These structs do not follow any of the previous rules. Some have special capabilities, for example simple structs like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt; are ''value objects'': they can be copied and passed around like any &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; would. Some others are strictly locked down and serve as very little beyond a way to keep a pointer safe. In general, when working with game API structs, assume they are what would be called ''move only'' in C++. And NimbyScript has no move operator or semantics, so in essence assume they are immutable, immobile references, except when documented otherwise (like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As an aside, all script declared &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; or not) are also always ''move only'', and always “owned” by some external entity. This is why the APIs for their manipulation are always based on pointers and references, even for private structs. It is not possible to create plain, stack allocated values of script structs, or to use them as fields in structs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version:&lt;br /&gt;
&lt;br /&gt;
* Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
* Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums)&lt;br /&gt;
* For pub structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* For private structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In pub structs these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types. &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; will also display a small list editor. Keep in mind the correct type is &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;Vec&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- 'let' BindBody 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- 'let' BindBody ';'&lt;br /&gt;
BindBody    &amp;amp;lt;- NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' 'let' BindBody BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- ColonNAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere pointer types cannot be dereferenced, therefore cannot be used in dot expressions. The exception is the built-in function &amp;lt;code&amp;gt;is_valid(ptr): bool&amp;lt;/code&amp;gt;, which is usable with any pointer type.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;extensions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Extensions =&lt;br /&gt;
&lt;br /&gt;
Extending game database struct data with &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt; can also be used to extend the game code. The mechanism to do so is to first declare a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;ing a game database object (with or without fields). Then create a specifically named and parametrized function which will be called by the game under certain situations, for certain kinds of objects.&lt;br /&gt;
&lt;br /&gt;
All extension functions take a &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter which is a reference to the struct which it is method of, called &amp;lt;code&amp;gt;Example&amp;lt;/code&amp;gt; in the following sections. Replace it with your struct name. The rest of the parameters are fixed and must be reproduced exactly as-is.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
Event functions are called as part of the core simulation engine. They are meant to be focused in features and quick to execute. These functions might be called thousands of times per simulation frame, including multiple redundant times. Their capability to change the simulation behavior is usually very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_check&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_check ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails, or if another script call returns &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_lookahead&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_lookahead ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_lookahead(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    train_distance: f64,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalLookaheadResult&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; function at regular intervals for each signal 15km ahead of the train path. It is called for all signals, until one of these conditions hold:&lt;br /&gt;
&lt;br /&gt;
* One of the signals path checks as &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;&lt;br /&gt;
* Another train is found&lt;br /&gt;
* The train stop is found&lt;br /&gt;
* 15km have been checked&lt;br /&gt;
&lt;br /&gt;
For both &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; signals, your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; will be called, and you can check the path find result in &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;, and the distance from the train in &amp;lt;code&amp;gt;train_distance&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; allows to set a maximum speed for the train, which goes into effect immediately. This works from any distance and past any amount of signals between the train and the caller signal. If multiple signals in the lookahead path return a &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt;, the slowest speed is picked. If no &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt; is set, or it is 0, the result is ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; default value is 0, which is considered invalid and will be ignored. To stop the train at the signal implement &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_change_path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_change_path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_change_path(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The current path check result of this signal for the passed train is passed as &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;. This already includes any results from &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_pass_by&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_pass_by ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_pass_by(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; function on the exact simulation frame a train passes by the exact point of the signal on the track.&lt;br /&gt;
&lt;br /&gt;
This function has no return result. Instead, since it has a predictably low call rate compared to the other events, it is the only event function with access to the powerful &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_marker_reserved&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_marker_reserved ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given marker signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; any time the reservation check algorithm is tracing a path which goes over the marker signal, on any direction, giving it the chance to report an arbitrary train as the reserver of that point on the track.&lt;br /&gt;
&lt;br /&gt;
This signal has a potential huge call rate, and for this reason it is given very little access to the APIs. The intention is that all the state required by this signal is calculated somewhere else and attached to the signal as a private struct object, or to some object reachable from it. Don’t worry about filtering for the “same train” cases, this is automatically done.&lt;br /&gt;
&lt;br /&gt;
If no reservation is desired, use the &amp;lt;code&amp;gt;empty&amp;lt;/code&amp;gt; global method available in all &amp;lt;code&amp;gt;ID&amp;amp;lt;Class&amp;amp;gt;&amp;lt;/code&amp;gt; types: &amp;lt;code&amp;gt;return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {}&lt;br /&gt;
struct Owner {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; {&lt;br /&gt;
    // some other, more full featured script function has attached Owner to this signal,&lt;br /&gt;
    // or not, so we need to check first&lt;br /&gt;
    if let owner &amp;amp;amp;= db.view&amp;amp;lt;Owner&amp;amp;gt;(signal) {&lt;br /&gt;
        if is_valid(db.view(owner.train_id)) {&lt;br /&gt;
            return owner.train_id;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_texture_state&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_texture_state ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_texture_state(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    clock_us: i64&lt;br /&gt;
): i64 { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment, when the game UI needs to query what is the current signal texture state index, it will call your &amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt;, with some potential caching to keep the call rate lower. In any case the call rate of this function is potentially very large when the user zooms out the map, so make sure to keep its code as efficient as possible. For this same reason it is given very little access to the APIs. &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; is the number of sim-microseconds since the current save was created, you use it with the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; functions to make animations.&lt;br /&gt;
&lt;br /&gt;
The return value indicates which signal texture state is to be used. If it’s -1 or lower, the default algorithm will be used to select the texture index. If it’s 0 or larger, it will select the texture in the same order as the &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; lines in the &amp;lt;code&amp;gt;SignalTextures&amp;lt;/code&amp;gt;. Larger values than the number of states will be clamped to the last state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_setup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_setup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_setup(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ss: &amp;amp;amp;mut ShiftSetup&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when an unassigned train decides to lookup a new shift to run, it will first call &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The parameter &amp;lt;code&amp;gt;ss&amp;lt;/code&amp;gt; is both an input and output parameter. It is initialized with the current, relevant data for the given train state, and &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; can then change it, to influence which shifts will be considered by the shift selection algorithm. It can change the train position used for matching, the time used for matching, and disable the check for reservations. For matched shifts which do not correspond to the current train position, the Extrapolator system will automatically pathfind a temporary milestone for the train, like other path-changing features.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_allow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_allow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_allow(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    run: &amp;amp;amp;Run,&lt;br /&gt;
    stop_idx: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    pose: &amp;amp;amp;Pose&lt;br /&gt;
): ShiftAllow { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when the shift selection algorithm fins a valid shift for the given train, it will call &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; with all the relevant data. The return of the function can then allow or deny the shift. If the shift is denied, the algorithm will resume immediately, trying other shifts&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are independent from each other, and can be used in any combination.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;linestop-event_line_stop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Line::Stop event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestStop extend Line::Stop {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestStop::event_line_stop(&lt;br /&gt;
    self: &amp;amp;amp;TestStop,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == LineStopEvent::Arrive {&lt;br /&gt;
        log(&amp;amp;quot;@ arrives @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ departs @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given line stop in the line editor. From that moment, when any train arrives or departs said line stop, &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LineStopEvent::Depart&amp;lt;/code&amp;gt; to distinguish between arrival and departure. Waypoints are only called for &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt;. Shift-less trains are also called.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;shift-event_shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Shift event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestShift extend Shift {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestShift::event_shift(&lt;br /&gt;
    self: &amp;amp;amp;TestShift,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == ShiftEvent::Assign {&lt;br /&gt;
        log(&amp;amp;quot;@ assigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ unassigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given schedule shift in the line editor. From that moment, when any train is assigned to the shift, or becomes unassigned from the shift, &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;ShiftEvent::Assign&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ShiftEvent::Unassign&amp;lt;/code&amp;gt; to distinguish between assignation and unassignation. The &amp;lt;code&amp;gt;Assign&amp;lt;/code&amp;gt; event is called just after &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been set up, so it already has all the shift and run information. The &amp;lt;code&amp;gt;Unassign&amp;lt;/code&amp;gt; event is called just before &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been cleared of all shift and run information so the script has access to as much information as possible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;global-events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Global events ==&lt;br /&gt;
&lt;br /&gt;
Like event functions of struct extensions, global events are called as part of the core simulation engine when a specific event occurs, but they are not associated to any struct. Instead they are public top level functions with the signature given in this document. Global event functions are always called if they exist in a script and the event occurs.&lt;br /&gt;
&lt;br /&gt;
=== global_event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn global_event_line_stop(&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    log(&amp;amp;quot;global_event_line_stop: @ on line @&amp;amp;quot;, train, line);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Arguments and conditions are identical to &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt;, except there is no &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter.&lt;br /&gt;
&lt;br /&gt;
=== global_event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn global_event_shift(&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    log(&amp;amp;quot;global_event_shift: @ on sched @&amp;amp;quot;, train, sched);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Arguments and conditions are identical to &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt;, except there is no &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;controllers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Controllers ==&lt;br /&gt;
&lt;br /&gt;
Controller functions are called at a low frame rate compared to the overall simulation, with an (unchangeable) rate of once in 6 sim-seconds. They do not need any specific event or trigger to run, other than their enforced timer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-control_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train control_train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct HateDepots extend Train {}&lt;br /&gt;
pub fn HateDepots::control_train(&lt;br /&gt;
    self: &amp;amp;amp;HateDepots,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    // train is already removed from the tracks, don't interfere with potential attempts at shift assignation&lt;br /&gt;
    if !is_valid(motion.presence.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is running a schedule, don't interfere&lt;br /&gt;
    if is_valid(motion.schedule_dispatch.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is present, but it is not running a schedule, so despawn it&lt;br /&gt;
    sc.queue_train_intervention(train);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The train motion engine will call train controllers in the multithreaded phase, as part of the regular train motion extrapolator, after all the C++ code is done for a frame for a particular train, but before any queued commands are executed. Command execution will only happen after all train controllers for a given frame are done. In other words, train controllers queue up work to be executed by the sim. They never directly change the sim in any way, allowing train controller execution to be fully parallel.&lt;br /&gt;
&lt;br /&gt;
After all controllers are run, and all their non-task commands are executed, and then tasks are executed. Read more about tasks later on. Any tasks with a deadline which expired in this frame a run at this time too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontroller-command-queue&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== SimController command queue ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; object implements an API to control the simulation, including modification of some parameters and behaviors. It is also responsible for attaching and erasing private struct data from game objects, on behalf of scripts. The execution of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; is based on a command queue. Every call queues a command and returns immediately to the script code, without making any changes to the game state. Therefore the game state never changes while the script code is running.&lt;br /&gt;
&lt;br /&gt;
Commands queued from events and &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt; are executed asynchronously, there is no guaranteed order of execution! You must prepare your code and data for this design. For stand alone tasks scripts commands are executed in order and in isolation. You can queue up tasks from event and control scripts when you need to guarantee data consistency beyond “pick a random winner”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SimpleSimController&amp;lt;/code&amp;gt; is a cut down version of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; for high frequency events like &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt;. The reference in the second part of this document lists which &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; functions are available in &amp;lt;code&amp;gt;SimpleSimController&amp;lt;/code&amp;gt;, and they work identically.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_intervention&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_intervention ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks, releases its schedule shift (if any), and deletes and refunds its pax (if any). No other cost other than pax refunds is issued. This function can be used as a general “despawn the train” feature, not just for exceptional circumstances.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_warp&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_warp ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks and repositions it at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, re-pathing it to its currently scheduled destination (if any), and setting its speed to 0. This is basically a train wormhole. The train keeps its shift and pax, if any.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_drive_to&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_drive_to ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Re-paths the train path to end at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, without any changes to its shift or pax (if any). It is possible for any future &amp;lt;code&amp;gt;queue_train_drive_to&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; to reset this path at any point, losing the destination. “Queue” here is used as part of the SimController API semantics, it does not mean the train keeps a queue of positions to reach. If the path is not interrupted and the train reaches &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; it will re-path itself towards its current scheduled stop, if it has any, or brake to a stop if unassigned. If &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; was also in the stop area set for its current scheduled stop it will also brake to stop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_attach&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_attach ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the attachment of the &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;existing.clone()&amp;lt;/code&amp;gt;) to the &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt;, which must be of one of the following types: &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attached objects can be accessed with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt; at some point in the future. If called from a controller function, the attached object will be accessible after all controller functions are done for a given frame. If called from a task, he attached object will be accessible immediately after the task returns, and before any other task is executed. In other words, tasks are transaction-like, in the sense they view an immutable snapshot of the game state, and any changes they queue are executed before any other task, and then visible from these other tasks.&lt;br /&gt;
&lt;br /&gt;
Attaching an object of a given private struct type when it already exists attached to a &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt; will overwrite it. This is how private data is updated from scripting: by using &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; to copy any existing data, modifying the copy, then calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; to replace the existing data. Therefore it is a good idea to keep your private structs small. Only one instance of a given private struct type can be attached to any particular model object, but you can attach as many different private struct types as you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_erase&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_erase ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the erasure of &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt;, which must obtained using with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt;. Trying to erase temporary objects (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;existing.clone()&amp;lt;/code&amp;gt;) is ignored. The execution of the queued erase commands is analog to the &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; case. In particular a sequences of attach and erase queued from controllers will produce undefined results (impossible to predict which attach and/or erase wins). For example multiple attach from a controller for the same model_obj and private struct type will implicitly pick a singular “winner” attach, but the script does not have any control over which one. Sequences of attach and erase queued from tasks are strictly ordered and isolated, so they produce consistent results, in the same order they were queued in the task script, without any concurrent changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task-and-simcontrollerqueue_task_at&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task and SimController::queue_task_at ===&lt;br /&gt;
&lt;br /&gt;
See [[#Control%20tasks|control tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task_event_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task_event_train ===&lt;br /&gt;
&lt;br /&gt;
See [[#Event%20tasks|event tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;control-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Control tasks ==&lt;br /&gt;
&lt;br /&gt;
Control tasks are a very special kind of command which allows scripts to dynamically queue “future work”, with privileged access to the sim. Scripts with access to &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; can call this function to queue up a task for future script execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; must be of a private struct type which implements &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example { ... }&lt;br /&gt;
pub fn Example::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
For example, a train controller script could decide it needs to delay some decision into a task for data consistency reasons (other controllers are running at the same time), and delegate into a task rather than directly calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ControlTrain extend Train { ... }&lt;br /&gt;
pub fn ControlTrain::control_train(&lt;br /&gt;
    self: &amp;amp;amp;ControlTrain,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    task.train_id = train.id;&lt;br /&gt;
    task.v = some_data_from_somewhere;&lt;br /&gt;
    task.prio = 42; // or something smarter, like from ControlTrain, other objects, etc.&lt;br /&gt;
    sc.queue_task(task);&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
struct Task {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
struct SomeData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
pub fn Task::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    let train &amp;amp;amp;= ctx.db.view(self.train_id) else { return; }&lt;br /&gt;
    if let existing &amp;amp;amp;= ctx.db.view&amp;amp;lt;SomeData&amp;amp;gt;(train) {&lt;br /&gt;
        if existing.prio &amp;amp;gt;= self.prio {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    let data = SomeData::new();&lt;br /&gt;
    data.v = self.v;&lt;br /&gt;
    data.prio = self.prio;&lt;br /&gt;
    sc.queue_attach(train, data);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the previous example, maybe &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; will be called multiple times because multiple &amp;lt;code&amp;gt;ControlTrain::control_train()&amp;lt;/code&amp;gt; instances queued objects of &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;, but each execution will be single threaded, and all its queued &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; commands will be executed just after the call is done and before any other &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; call (for &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; or any other struct type), therefore the algorithm to pick a winner based on an explicit priority works.&lt;br /&gt;
&lt;br /&gt;
As mentioned, task execution is single threaded. The game does not feature a real concurrent database, instead all concurrent access is bespoke and very carefully designed to avoid deadlocks and inconsistencies (this is much faster than a general purpose concurrent database). Scripts also run in this parallel system, but their access to the game state is carefully restricted as explained earlier. But in the end, scripts also need to modify data, and do so in a consistent way. Tasks solve this issue, but do so in the most pessimistic possible way, by being single threaded. Therefore script developers should use them in moderation. Consider the “random winner” semantics of control script queuing first, which are completely free performance wise, before deciding you need a task. It is often the case a concurrent problem reduces to “pick 0 or 1 winners, any winner, but never 2 or more” and the default queue semantics already provide that guarantee for attaching a specific model/private pair.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; is provided with &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt;, therefore it can queue tasks itself. But unlike controller queuing tasks, which are guaranteed to run on the same frame, tasks queued from tasks are guaranteed to ''not'' run on the same frame, on purpose. They are deliberately stored away and forced a delay of 6 sim-seconds. This is to avoid misuse of tasks, and infinite looping.&lt;br /&gt;
&lt;br /&gt;
This behavior might even be desirable in certain scripts, for example if you are developing some stateful signal system and you need some kind of “cleanup” task that makes sure some signal being owned by some train is still the focus of said train. You can deliberately queue tasks for future simulation frames with &amp;lt;code&amp;gt;queue_task_at&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;deadline&amp;lt;/code&amp;gt; is expressed as microseconds since the start of the current save world. You can obtain the current simulation frame &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; value with &amp;lt;code&amp;gt;Extrapolator::clock_us()&amp;lt;/code&amp;gt;, like in this example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;    // schedule task to run 10 sim-s from now&lt;br /&gt;
    sc.queue_task_at(task, ctx.extrapolator.clock_us() + 10000000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;event-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Event tasks ==&lt;br /&gt;
&lt;br /&gt;
Event tasks are a lightweight version of tasks which run when triggered by certain events. Unlike control tasks, event tasks do not have unlimited access to the sim. Instead the run under an &amp;lt;code&amp;gt;EventCtx&amp;lt;/code&amp;gt; like pub struct events, and run multithreaded, at the same time as the C++ code. Unlike the regular &amp;lt;code&amp;gt;event_*&amp;lt;/code&amp;gt; methods, event tasks are queued for execution by script code, not by UI player commands. The design idea of these tasks is to offer a more focused and efficient execution model than &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt;: they are executed immediately once the relevant event happens, in multithreaded context, rather than require passive polling which might even miss certain events and force execution of single thread code.&lt;br /&gt;
&lt;br /&gt;
Any function with a &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; parameter can queue an even task like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Task {...}&lt;br /&gt;
fn f(..., train: &amp;amp;amp;Train, sc: &amp;amp;amp;mut SimController) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    sc.queue_task_event_train(task, train, TaskEventTrain::StopDepart);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
On the next stop departure of the train the &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt; method will be called:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn Task::task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: TaskEventTrain,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == TaskEventTrain::StopDepart {&lt;br /&gt;
        log(&amp;amp;quot;@ departs&amp;amp;quot;, train);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Like control tasks, event tasks encapsulate a single call. If a series of calls are desired, the task can requeue itself by calling &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt;. Event tasks are limited to a maximum of 1 for every possible train-struct-event combination, to avoid leaks. Trying to queue again the same train-struct-event combination will overwrite any existing task. Only the train and motion are provided as parameters. The code can then drill into motion to extract any required information, like shift or line.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-controlctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ControlCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ControlCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    sim: &amp;amp;amp;Sim,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim controller scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects, and associated script stuct objects.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::track_pos_project(self: &amp;amp;amp;DB, pos: &amp;amp;amp;Pos, distance: f64): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return a track position separated by ‘distance’ meters from ‘pos’, in the direction of ‘pos’. If distance is negative it will be in the opposite direction. Can only follow the main track. Merges and dead ends will return a Pos a shorter distance away. Signals are ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view_self(self: &amp;amp;amp;DB): &amp;amp;amp;Script&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-eventctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type EventCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct EventCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim event handler scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line::Stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line::Stop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    cars_config: i32,&lt;br /&gt;
    dynamics: Train::Dynamics,&lt;br /&gt;
    hitched_by: Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    station_stop: std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;,&lt;br /&gt;
    run_stop: std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
    run_dispatch: std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;,&lt;br /&gt;
    hitch: std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motioncachedhitcher&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::CachedHitcher ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::CachedHitcher {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionhitch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Hitch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Hitch {&lt;br /&gt;
    driver_train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    flip: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Train is being hitched by a driver train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
    flip: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionrundispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::RunDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::RunDispatch {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a line run.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Motion::RunDispatch::current_stop(self: &amp;amp;amp;Motion::RunDispatch, line: &amp;amp;amp;Line): *Line::Stop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionstationstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::StationStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::StationStop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Schedule::view(self: &amp;amp;amp;Schedule, shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;): *Shift&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns a pointer to the shift, if it’s contained in this schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-script&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Script ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Script {&lt;br /&gt;
    id: ID&amp;amp;lt;Script&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Shift {&lt;br /&gt;
    id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::kind(self: &amp;amp;amp;Signal): mut SignalKind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the signal kind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Track::max_speed(self: &amp;amp;amp;Track): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the min(physical, manual setting) max speed of the track, in m/s.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-traindynamics&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train::Dynamics ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train::Dynamics {&lt;br /&gt;
    max_speed: f32,&lt;br /&gt;
    max_acceleration: f32,&lt;br /&gt;
    max_regular_braking: f32,&lt;br /&gt;
    max_emergency_braking: f32,&lt;br /&gt;
    max_tractive_effort: f32,&lt;br /&gt;
    total_power: f32,&lt;br /&gt;
    empty_mass: f32,&lt;br /&gt;
    length: f32,&lt;br /&gt;
    max_pax: i32,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vec&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;lt;Motion::CachedHitcher&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Hitch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;): *Motion::Hitch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStationEvent&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;&lt;br /&gt;
): *Motion::StationStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Script&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Shift&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Shift&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Shift&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciterator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;lt;Motion::CachedHitcher&amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator::next(&lt;br /&gt;
    self: &amp;amp;amp;mut Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator&lt;br /&gt;
): *Motion::CachedHitcher&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    idx: i64&lt;br /&gt;
): *Motion::CachedHitcher&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::clock_us(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current microseconds since the creation of this saved game. This is used as the timing root of the simulation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second since 1970-01-01:00:00:00.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_occupation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_reservation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying or reserving the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_occupying(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_reserving(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying or reserving the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
Probe a track position for train reservations and occupations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Seconds since 1970-01-01:00:00:00 for Monday 00:00:00 of the current week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestopevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type LineStopEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum LineStopEvent {&lt;br /&gt;
    Arrive,&lt;br /&gt;
    Depart,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
Advance the iterator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftallow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftAllow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftAllow {&lt;br /&gt;
    Allow,&lt;br /&gt;
    Deny,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftEvent {&lt;br /&gt;
    Assign,&lt;br /&gt;
    Unassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftsetup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftSetup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ShiftSetup {&lt;br /&gt;
    skip: bool,&lt;br /&gt;
    match_pos: bool,&lt;br /&gt;
    check_occupation: bool,&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores the context of a train shift lookup.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function wants to change the train path, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signallookaheadresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalLookaheadResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalLookaheadResult {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores extra information associated with the result of the signal lookahead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-sim&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Sim ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Sim {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of the simulation state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Sim::view&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Sim, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A proxy mutable API to the simulation engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    ev: TaskEventTrain&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_hitch(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    driver: &amp;amp;amp;Train,&lt;br /&gt;
    hitcher: &amp;amp;amp;Train,&lt;br /&gt;
    order: i64,&lt;br /&gt;
    flip: bool&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hitch a train to a driver train. The hitched train is emptied of pax and removed from the sim, while its cars are appended to the driver. The order parameter (from -1000 to 1000) determines the hitched train cars position: the driver train is always order 0, so negative values will put the hitch in front of the driver, and positive values behind it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(self: &amp;amp;amp;mut SimController, train: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_run_line(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    arrival_offset_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_configuration(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    config: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_presence_flip(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    flip: bool&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_stop_delay(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    delay_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add extra delay time to a stopped train that has a timed_stop component.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_unhitch(self: &amp;amp;amp;mut SimController, hitcher: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Remove the hitched state from a train. It will become an unspawned, unassigned train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simplesimcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimpleSimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimpleSimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A limited API version of SimController.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimpleSimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimpleSimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-taskeventtrain&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TaskEventTrain ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum TaskEventTrain {&lt;br /&gt;
    StopArrive,&lt;br /&gt;
    StopDepart,&lt;br /&gt;
    ShiftAssign,&lt;br /&gt;
    ShiftUnassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=558</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=558"/>
		<updated>2026-01-18T18:43:49Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used in game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration, integer division or arbitrary setting of pointers and references, and most data exposed to scripts is read-only, strictly enforced by the language. Any expression result which could result in an out of bounds or invalid memory access must be checked for validity, and the API design together with the type system enforces it.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
pub struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;SpeedTrap,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- VisMod? 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' ColonNAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Script&amp;lt;/code&amp;gt; (with restrictions)&lt;br /&gt;
&lt;br /&gt;
Structs extending game types for player extensions must be declared as &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt;. When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
To read struct objects from script code they must be looked up using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API. Therefore only functions provided with &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt; object (or a context object with contains &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt;) can look up these objects. But you can pass around &amp;lt;code&amp;gt;DB&amp;amp;amp;&amp;lt;/code&amp;gt; as a parameter without any lifetime restrictions, since it’s a purely read only API. This API also works for non-pub structs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= ctx.db.view&amp;amp;lt;Example&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    log(&amp;amp;quot;v = @&amp;amp;quot;, config.v);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;pub-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== pub structs ====&lt;br /&gt;
&lt;br /&gt;
As explained earlier, &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs are the user interface of your scripts. They are exposed in the UI as input forms, and their &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;s can give some control over this rendering. Conceptually they are owned by the player of the game as part of the game object database, by attaching them to a game model object in the database, not the script. Scripts do not have any capability to create, edit or delete objects of &amp;lt;code&amp;gt;pub struct&amp;lt;/code&amp;gt;s. It is always the player who decides when to create a new object of these structs by interacting in the UI. Scripts can then read, and only read, the content of these objects, by using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API presented earlier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs have a very powerful capability: they have limited support for forward schema evolution. This means that the script developer can add to, and reorder, fields in &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, and the game runtime will be able keep the contents of the other fields intact. This is very important to respect the input data by the player. If you rename &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs or their fields, or change their types, the player input data will be lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;non-pub-or-private-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Non-pub (or private) structs ====&lt;br /&gt;
&lt;br /&gt;
Non-&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, also called private structs, are conceptually owned by the script as a part of the simulation, not the player. Their contents are assumed to be a black box by the rest of the game. Scripts are allowed to create and modify objects of these structs during their execution, which are automatically deleted at the end of the simulation frame. It is also possible to attach these structs to existing game model objects to extend their lifetime beyond the current frame. In this case their lifetime becomes the same as the game object, and they can be retrieved in later frames for reading, deleted or overwritten as desired.&lt;br /&gt;
&lt;br /&gt;
Private structs ''do not support schema evolution''. Changing field types, field names, reordering of fields, even just adding new fields at the end, will always result in losing all existing attached objects of the given struct. Some operations like resetting the simulation will also erase attached objects, because they are considered simulation state, not player created objects.&lt;br /&gt;
&lt;br /&gt;
Private structs support dynamic memory allocation. All private struct definitions automatically create a &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; method for the struct:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct PrivData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let ro &amp;amp;amp;= ctx.db.view&amp;amp;lt;PrivData&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    let rw &amp;amp;amp;mut= ro.clone();&lt;br /&gt;
    rw.v = 100;&lt;br /&gt;
    let empty &amp;amp;amp;mut= PrivData::new();&lt;br /&gt;
    empty.v = 200;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The objects allocated by &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; are always deleted at the end of the current simulation frame. Their lifetime can be extended beyond the current frame by attaching them to a game object, like &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, so their lifetime becomes the same as the attached object. The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API has methods for attaching and erasing these object.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;host-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Host structs ====&lt;br /&gt;
&lt;br /&gt;
Many of the exposed game APIs are also based around structs. These structs do not follow any of the previous rules. Some have special capabilities, for example simple structs like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt; are ''value objects'': they can be copied and passed around like any &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; would. Some others are strictly locked down and serve as very little beyond a way to keep a pointer safe. In general, when working with game API structs, assume they are what would be called ''move only'' in C++. And NimbyScript has no move operator or semantics, so in essence assume they are immutable, immobile references, except when documented otherwise (like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As an aside, all script declared &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; or not) are also always ''move only'', and always “owned” by some external entity. This is why the APIs for their manipulation are always based on pointers and references, even for private structs. It is not possible to create plain, stack allocated values of script structs, or to use them as fields in structs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version:&lt;br /&gt;
&lt;br /&gt;
* Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
* Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums)&lt;br /&gt;
* For pub structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* For private structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In pub structs these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types. &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; will also display a small list editor. Keep in mind the correct type is &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;Vec&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- 'let' BindBody 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- 'let' BindBody ';'&lt;br /&gt;
BindBody    &amp;amp;lt;- NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' 'let' BindBody BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- ColonNAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere pointer types cannot be dereferenced, therefore cannot be used in dot expressions. The exception is the built-in function &amp;lt;code&amp;gt;is_valid(ptr): bool&amp;lt;/code&amp;gt;, which is usable with any pointer type.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;extensions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Extensions =&lt;br /&gt;
&lt;br /&gt;
Extending game database struct data with &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt; can also be used to extend the game code. The mechanism to do so is to first declare a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;ing a game database object (with or without fields). Then create a specifically named and parametrized function which will be called by the game under certain situations, for certain kinds of objects.&lt;br /&gt;
&lt;br /&gt;
All extension functions take a &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter which is a reference to the struct which it is method of, called &amp;lt;code&amp;gt;Example&amp;lt;/code&amp;gt; in the following sections. Replace it with your struct name. The rest of the parameters are fixed and must be reproduced exactly as-is.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
Event functions are called as part of the core simulation engine. They are meant to be focused in features and quick to execute. These functions might be called thousands of times per simulation frame, including multiple redundant times. Their capability to change the simulation behavior is usually very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_check&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_check ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails, or if another script call returns &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_lookahead&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_lookahead ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_lookahead(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    train_distance: f64,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalLookaheadResult&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; function at regular intervals for each signal 15km ahead of the train path. It is called for all signals, until one of these conditions hold:&lt;br /&gt;
&lt;br /&gt;
* One of the signals path checks as &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;&lt;br /&gt;
* Another train is found&lt;br /&gt;
* The train stop is found&lt;br /&gt;
* 15km have been checked&lt;br /&gt;
&lt;br /&gt;
For both &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; signals, your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; will be called, and you can check the path find result in &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;, and the distance from the train in &amp;lt;code&amp;gt;train_distance&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; allows to set a maximum speed for the train, which goes into effect immediately. This works from any distance and past any amount of signals between the train and the caller signal. If multiple signals in the lookahead path return a &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt;, the slowest speed is picked. If no &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt; is set, or it is 0, the result is ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; default value is 0, which is considered invalid and will be ignored. To stop the train at the signal implement &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_change_path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_change_path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_change_path(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The current path check result of this signal for the passed train is passed as &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;. This already includes any results from &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_pass_by&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_pass_by ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_pass_by(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; function on the exact simulation frame a train passes by the exact point of the signal on the track.&lt;br /&gt;
&lt;br /&gt;
This function has no return result. Instead, since it has a predictably low call rate compared to the other events, it is the only event function with access to the powerful &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_marker_reserved&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_marker_reserved ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given marker signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; any time the reservation check algorithm is tracing a path which goes over the marker signal, on any direction, giving it the chance to report an arbitrary train as the reserver of that point on the track.&lt;br /&gt;
&lt;br /&gt;
This signal has a potential huge call rate, and for this reason it is given very little access to the APIs. The intention is that all the state required by this signal is calculated somewhere else and attached to the signal as a private struct object, or to some object reachable from it. Don’t worry about filtering for the “same train” cases, this is automatically done.&lt;br /&gt;
&lt;br /&gt;
If no reservation is desired, use the &amp;lt;code&amp;gt;empty&amp;lt;/code&amp;gt; global method available in all &amp;lt;code&amp;gt;ID&amp;amp;lt;Class&amp;amp;gt;&amp;lt;/code&amp;gt; types: &amp;lt;code&amp;gt;return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {}&lt;br /&gt;
struct Owner {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; {&lt;br /&gt;
    // some other, more full featured script function has attached Owner to this signal,&lt;br /&gt;
    // or not, so we need to check first&lt;br /&gt;
    if let owner &amp;amp;amp;= db.view&amp;amp;lt;Owner&amp;amp;gt;(signal) {&lt;br /&gt;
        if is_valid(db.view(owner.train_id)) {&lt;br /&gt;
            return owner.train_id;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_texture_state&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_texture_state ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_texture_state(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    clock_us: i64&lt;br /&gt;
): i64 { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment, when the game UI needs to query what is the current signal texture state index, it will call your &amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt;, with some potential caching to keep the call rate lower. In any case the call rate of this function is potentially very large when the user zooms out the map, so make sure to keep its code as efficient as possible. For this same reason it is given very little access to the APIs. &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; is the number of sim-microseconds since the current save was created, you use it with the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; functions to make animations.&lt;br /&gt;
&lt;br /&gt;
The return value indicates which signal texture state is to be used. If it’s -1 or lower, the default algorithm will be used to select the texture index. If it’s 0 or larger, it will select the texture in the same order as the &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; lines in the &amp;lt;code&amp;gt;SignalTextures&amp;lt;/code&amp;gt;. Larger values than the number of states will be clamped to the last state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_setup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_setup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_setup(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ss: &amp;amp;amp;mut ShiftSetup&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when an unassigned train decides to lookup a new shift to run, it will first call &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The parameter &amp;lt;code&amp;gt;ss&amp;lt;/code&amp;gt; is both an input and output parameter. It is initialized with the current, relevant data for the given train state, and &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; can then change it, to influence which shifts will be considered by the shift selection algorithm. It can change the train position used for matching, the time used for matching, and disable the check for reservations. For matched shifts which do not correspond to the current train position, the Extrapolator system will automatically pathfind a temporary milestone for the train, like other path-changing features.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_allow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_allow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_allow(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    run: &amp;amp;amp;Run,&lt;br /&gt;
    stop_idx: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    pose: &amp;amp;amp;Pose&lt;br /&gt;
): ShiftAllow { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when the shift selection algorithm fins a valid shift for the given train, it will call &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; with all the relevant data. The return of the function can then allow or deny the shift. If the shift is denied, the algorithm will resume immediately, trying other shifts&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are independent from each other, and can be used in any combination.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;linestop-event_line_stop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Line::Stop event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestStop extend Line::Stop {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestStop::event_line_stop(&lt;br /&gt;
    self: &amp;amp;amp;TestStop,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == LineStopEvent::Arrive {&lt;br /&gt;
        log(&amp;amp;quot;@ arrives @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ departs @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given line stop in the line editor. From that moment, when any train arrives or departs said line stop, &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LineStopEvent::Depart&amp;lt;/code&amp;gt; to distinguish between arrival and departure. Waypoints are only called for &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt;. Shift-less trains are also called.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;shift-event_shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Shift event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestShift extend Shift {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestShift::event_shift(&lt;br /&gt;
    self: &amp;amp;amp;TestShift,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == ShiftEvent::Assign {&lt;br /&gt;
        log(&amp;amp;quot;@ assigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ unassigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given schedule shift in the line editor. From that moment, when any train is assigned to the shift, or becomes unassigned from the shift, &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;ShiftEvent::Assign&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ShiftEvent::Unassign&amp;lt;/code&amp;gt; to distinguish between assignation and unassignation. The &amp;lt;code&amp;gt;Assign&amp;lt;/code&amp;gt; event is called just after &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been set up, so it already has all the shift and run information. The &amp;lt;code&amp;gt;Unassign&amp;lt;/code&amp;gt; event is called just before &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been cleared of all shift and run information so the script has access to as much information as possible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;global-events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Global events ==&lt;br /&gt;
&lt;br /&gt;
Like event functions of struct extensions, global events are called as part of the core simulation engine when a specific event occurs, but they are not associated to any struct. Instead they are public top level functions with the signature given in this document. Global event functions are always called if they exist in a script and the event occurs.&lt;br /&gt;
&lt;br /&gt;
=== global_event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn global_event_line_stop(&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    log(&amp;amp;quot;global_event_line_stop: @ on line @&amp;amp;quot;, train, line);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Arguments and conditions are identical to &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt;, except there is no &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter.&lt;br /&gt;
&lt;br /&gt;
=== global_event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn global_event_shift(&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    log(&amp;amp;quot;global_event_shift: @ on sched @&amp;amp;quot;, train, sched);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Arguments and conditions are identical to &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt;, except there is no &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;controllers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Controllers ==&lt;br /&gt;
&lt;br /&gt;
Controller functions are called at a low frame rate compared to the overall simulation, with an (unchangeable) rate of once in 6 sim-seconds. They do not need any specific event or trigger to run, other than their enforced timer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-control_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train control_train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct HateDepots extend Train {}&lt;br /&gt;
pub fn HateDepots::control_train(&lt;br /&gt;
    self: &amp;amp;amp;HateDepots,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    // train is already removed from the tracks, don't interfere with potential attempts at shift assignation&lt;br /&gt;
    if !is_valid(motion.presence.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is running a schedule, don't interfere&lt;br /&gt;
    if is_valid(motion.schedule_dispatch.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is present, but it is not running a schedule, so despawn it&lt;br /&gt;
    sc.queue_train_intervention(train);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The train motion engine will call train controllers in the multithreaded phase, as part of the regular train motion extrapolator, after all the C++ code is done for a frame for a particular train, but before any queued commands are executed. Command execution will only happen after all train controllers for a given frame are done. In other words, train controllers queue up work to be executed by the sim. They never directly change the sim in any way, allowing train controller execution to be fully parallel.&lt;br /&gt;
&lt;br /&gt;
After all controllers are run, and all their non-task commands are executed, and then tasks are executed. Read more about tasks later on. Any tasks with a deadline which expired in this frame a run at this time too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontroller-command-queue&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== SimController command queue ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; object implements an API to control the simulation, including modification of some parameters and behaviors. It is also responsible for attaching and erasing private struct data from game objects, on behalf of scripts. The execution of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; is based on a command queue. Every call queues a command and returns immediately to the script code, without making any changes to the game state. Therefore the game state never changes while the script code is running.&lt;br /&gt;
&lt;br /&gt;
Commands queued from events and &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt; are executed asynchronously, there is no guaranteed order of execution! You must prepare your code and data for this design. For stand alone tasks scripts commands are executed in order and in isolation. You can queue up tasks from event and control scripts when you need to guarantee data consistency beyond “pick a random winner”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SimpleSimController&amp;lt;/code&amp;gt; is a cut down version of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; for high frequency events like &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt;. The reference in the second part of this document lists which &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; functions are available in &amp;lt;code&amp;gt;SimpleSimController&amp;lt;/code&amp;gt;, and they work identically.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_intervention&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_intervention ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks, releases its schedule shift (if any), and deletes and refunds its pax (if any). No other cost other than pax refunds is issued. This function can be used as a general “despawn the train” feature, not just for exceptional circumstances.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_warp&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_warp ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks and repositions it at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, re-pathing it to its currently scheduled destination (if any), and setting its speed to 0. This is basically a train wormhole. The train keeps its shift and pax, if any.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_drive_to&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_drive_to ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Re-paths the train path to end at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, without any changes to its shift or pax (if any). It is possible for any future &amp;lt;code&amp;gt;queue_train_drive_to&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; to reset this path at any point, losing the destination. “Queue” here is used as part of the SimController API semantics, it does not mean the train keeps a queue of positions to reach. If the path is not interrupted and the train reaches &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; it will re-path itself towards its current scheduled stop, if it has any, or brake to a stop if unassigned. If &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; was also in the stop area set for its current scheduled stop it will also brake to stop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_attach&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_attach ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the attachment of the &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;existing.clone()&amp;lt;/code&amp;gt;) to the &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt;, which must be of one of the following types: &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attached objects can be accessed with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt; at some point in the future. If called from a controller function, the attached object will be accessible after all controller functions are done for a given frame. If called from a task, he attached object will be accessible immediately after the task returns, and before any other task is executed. In other words, tasks are transaction-like, in the sense they view an immutable snapshot of the game state, and any changes they queue are executed before any other task, and then visible from these other tasks.&lt;br /&gt;
&lt;br /&gt;
Attaching an object of a given private struct type when it already exists attached to a &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt; will overwrite it. This is how private data is updated from scripting: by using &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; to copy any existing data, modifying the copy, then calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; to replace the existing data. Therefore it is a good idea to keep your private structs small. Only one instance of a given private struct type can be attached to any particular model object, but you can attach as many different private struct types as you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_erase&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_erase ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the erasure of &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt;, which must obtained using with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt;. Trying to erase temporary objects (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;existing.clone()&amp;lt;/code&amp;gt;) is ignored. The execution of the queued erase commands is analog to the &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; case. In particular a sequences of attach and erase queued from controllers will produce undefined results (impossible to predict which attach and/or erase wins). For example multiple attach from a controller for the same model_obj and private struct type will implicitly pick a singular “winner” attach, but the script does not have any control over which one. Sequences of attach and erase queued from tasks are strictly ordered and isolated, so they produce consistent results, in the same order they were queued in the task script, without any concurrent changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task-and-simcontrollerqueue_task_at&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task and SimController::queue_task_at ===&lt;br /&gt;
&lt;br /&gt;
See [[#Control%20tasks|control tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task_event_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task_event_train ===&lt;br /&gt;
&lt;br /&gt;
See [[#Event%20tasks|event tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;control-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Control tasks ==&lt;br /&gt;
&lt;br /&gt;
Control tasks are a very special kind of command which allows scripts to dynamically queue “future work”, with privileged access to the sim. Scripts with access to &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; can call this function to queue up a task for future script execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; must be of a private struct type which implements &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example { ... }&lt;br /&gt;
pub fn Example::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
For example, a train controller script could decide it needs to delay some decision into a task for data consistency reasons (other controllers are running at the same time), and delegate into a task rather than directly calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ControlTrain extend Train { ... }&lt;br /&gt;
pub fn ControlTrain::control_train(&lt;br /&gt;
    self: &amp;amp;amp;ControlTrain,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    task.train_id = train.id;&lt;br /&gt;
    task.v = some_data_from_somewhere;&lt;br /&gt;
    task.prio = 42; // or something smarter, like from ControlTrain, other objects, etc.&lt;br /&gt;
    sc.queue_task(task);&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
struct Task {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
struct SomeData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
pub fn Task::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    let train &amp;amp;amp;= ctx.db.view(self.train_id) else { return; }&lt;br /&gt;
    if let existing &amp;amp;amp;= ctx.db.view&amp;amp;lt;SomeData&amp;amp;gt;(train) {&lt;br /&gt;
        if existing.prio &amp;amp;gt;= self.prio {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    let data = SomeData::new();&lt;br /&gt;
    data.v = self.v;&lt;br /&gt;
    data.prio = self.prio;&lt;br /&gt;
    sc.queue_attach(train, data);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the previous example, maybe &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; will be called multiple times because multiple &amp;lt;code&amp;gt;ControlTrain::control_train()&amp;lt;/code&amp;gt; instances queued objects of &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;, but each execution will be single threaded, and all its queued &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; commands will be executed just after the call is done and before any other &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; call (for &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; or any other struct type), therefore the algorithm to pick a winner based on an explicit priority works.&lt;br /&gt;
&lt;br /&gt;
As mentioned, task execution is single threaded. The game does not feature a real concurrent database, instead all concurrent access is bespoke and very carefully designed to avoid deadlocks and inconsistencies (this is much faster than a general purpose concurrent database). Scripts also run in this parallel system, but their access to the game state is carefully restricted as explained earlier. But in the end, scripts also need to modify data, and do so in a consistent way. Tasks solve this issue, but do so in the most pessimistic possible way, by being single threaded. Therefore script developers should use them in moderation. Consider the “random winner” semantics of control script queuing first, which are completely free performance wise, before deciding you need a task. It is often the case a concurrent problem reduces to “pick 0 or 1 winners, any winner, but never 2 or more” and the default queue semantics already provide that guarantee for attaching a specific model/private pair.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; is provided with &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt;, therefore it can queue tasks itself. But unlike controller queuing tasks, which are guaranteed to run on the same frame, tasks queued from tasks are guaranteed to ''not'' run on the same frame, on purpose. They are deliberately stored away and forced a delay of 6 sim-seconds. This is to avoid misuse of tasks, and infinite looping.&lt;br /&gt;
&lt;br /&gt;
This behavior might even be desirable in certain scripts, for example if you are developing some stateful signal system and you need some kind of “cleanup” task that makes sure some signal being owned by some train is still the focus of said train. You can deliberately queue tasks for future simulation frames with &amp;lt;code&amp;gt;queue_task_at&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;deadline&amp;lt;/code&amp;gt; is expressed as microseconds since the start of the current save world. You can obtain the current simulation frame &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; value with &amp;lt;code&amp;gt;Extrapolator::clock_us()&amp;lt;/code&amp;gt;, like in this example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;    // schedule task to run 10 sim-s from now&lt;br /&gt;
    sc.queue_task_at(task, ctx.extrapolator.clock_us() + 10000000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;event-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Event tasks ==&lt;br /&gt;
&lt;br /&gt;
Event tasks are a lightweight version of tasks which run when triggered by certain events. Unlike control tasks, event tasks do not have unlimited access to the sim. Instead the run under an &amp;lt;code&amp;gt;EventCtx&amp;lt;/code&amp;gt; like pub struct events, and run multithreaded, at the same time as the C++ code. Unlike the regular &amp;lt;code&amp;gt;event_*&amp;lt;/code&amp;gt; methods, event tasks are queued for execution by script code, not by UI player commands. The design idea of these tasks is to offer a more focused and efficient execution model than &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt;: they are executed immediately once the relevant event happens, in multithreaded context, rather than require passive polling which might even miss certain events and force execution of single thread code.&lt;br /&gt;
&lt;br /&gt;
Any function with a &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; parameter can queue an even task like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Task {...}&lt;br /&gt;
fn f(..., train: &amp;amp;amp;Train, sc: &amp;amp;amp;mut SimController) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    sc.queue_task_event_train(task, train, TaskEventTrain::StopDepart);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
On the next stop departure of the train the &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt; method will be called:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn Task::task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: TaskEventTrain,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == TaskEventTrain::StopDepart {&lt;br /&gt;
        log(&amp;amp;quot;@ departs&amp;amp;quot;, train);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Like control tasks, event tasks encapsulate a single call. If a series of calls are desired, the task can requeue itself by calling &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt;. Event tasks are limited to a maximum of 1 for every possible train-struct-event combination, to avoid leaks. Trying to queue again the same train-struct-event combination will overwrite any existing task. Only the train and motion are provided as parameters. The code can then drill into motion to extract any required information, like shift or line.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-controlctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ControlCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ControlCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    sim: &amp;amp;amp;Sim,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim controller scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects, and associated script stuct objects.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::track_pos_project(self: &amp;amp;amp;DB, pos: &amp;amp;amp;Pos, distance: f64): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return a track position separated by ‘distance’ meters from ‘pos’, in the direction of ‘pos’. If distance is negative it will be in the opposite direction. Can only follow the main track. Merges and dead ends will return a Pos a shorter distance away. Signals are ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view_self(self: &amp;amp;amp;DB): &amp;amp;amp;Script&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-eventctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type EventCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct EventCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim event handler scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line::Stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line::Stop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    cars_config: i32,&lt;br /&gt;
    dynamics: Train::Dynamics,&lt;br /&gt;
    hitched_by: Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    station_stop: std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;,&lt;br /&gt;
    run_stop: std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
    run_dispatch: std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;,&lt;br /&gt;
    hitch: std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motioncachedhitcher&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::CachedHitcher ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::CachedHitcher {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionhitch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Hitch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Hitch {&lt;br /&gt;
    driver_train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    flip: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Train is being hitched by a driver train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
    flip: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionrundispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::RunDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::RunDispatch {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a line run.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Motion::RunDispatch::current_stop(self: &amp;amp;amp;Motion::RunDispatch, line: &amp;amp;amp;Line): *Line::Stop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionstationstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::StationStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::StationStop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Schedule::view(self: &amp;amp;amp;Schedule, shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;): *Shift&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns a pointer to the shift, if it’s contained in this schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-script&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Script ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Script {&lt;br /&gt;
    id: ID&amp;amp;lt;Script&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Shift {&lt;br /&gt;
    id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::kind(self: &amp;amp;amp;Signal): mut SignalKind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the signal kind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-traindynamics&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train::Dynamics ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train::Dynamics {&lt;br /&gt;
    max_speed: f32,&lt;br /&gt;
    max_acceleration: f32,&lt;br /&gt;
    max_regular_braking: f32,&lt;br /&gt;
    max_emergency_braking: f32,&lt;br /&gt;
    max_tractive_effort: f32,&lt;br /&gt;
    total_power: f32,&lt;br /&gt;
    empty_mass: f32,&lt;br /&gt;
    length: f32,&lt;br /&gt;
    max_pax: i32,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vec&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;lt;Motion::CachedHitcher&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Hitch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;): *Motion::Hitch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStationEvent&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;&lt;br /&gt;
): *Motion::StationStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Script&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Shift&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Shift&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Shift&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciterator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;lt;Motion::CachedHitcher&amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator::next(&lt;br /&gt;
    self: &amp;amp;amp;mut Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator&lt;br /&gt;
): *Motion::CachedHitcher&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    idx: i64&lt;br /&gt;
): *Motion::CachedHitcher&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::clock_us(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current microseconds since the creation of this saved game. This is used as the timing root of the simulation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second since 1970-01-01:00:00:00.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_occupation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_reservation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying or reserving the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_occupying(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_reserving(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying or reserving the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
Probe a track position for train reservations and occupations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Seconds since 1970-01-01:00:00:00 for Monday 00:00:00 of the current week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestopevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type LineStopEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum LineStopEvent {&lt;br /&gt;
    Arrive,&lt;br /&gt;
    Depart,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
Advance the iterator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftallow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftAllow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftAllow {&lt;br /&gt;
    Allow,&lt;br /&gt;
    Deny,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftEvent {&lt;br /&gt;
    Assign,&lt;br /&gt;
    Unassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftsetup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftSetup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ShiftSetup {&lt;br /&gt;
    skip: bool,&lt;br /&gt;
    match_pos: bool,&lt;br /&gt;
    check_occupation: bool,&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores the context of a train shift lookup.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function wants to change the train path, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signallookaheadresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalLookaheadResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalLookaheadResult {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores extra information associated with the result of the signal lookahead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-sim&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Sim ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Sim {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of the simulation state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Sim::view&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Sim, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A proxy mutable API to the simulation engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    ev: TaskEventTrain&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_hitch(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    driver: &amp;amp;amp;Train,&lt;br /&gt;
    hitcher: &amp;amp;amp;Train,&lt;br /&gt;
    order: i64,&lt;br /&gt;
    flip: bool&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hitch a train to a driver train. The hitched train is emptied of pax and removed from the sim, while its cars are appended to the driver. The order parameter (from -1000 to 1000) determines the hitched train cars position: the driver train is always order 0, so negative values will put the hitch in front of the driver, and positive values behind it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(self: &amp;amp;amp;mut SimController, train: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_run_line(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    arrival_offset_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_configuration(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    config: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_presence_flip(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    flip: bool&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_stop_delay(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    delay_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add extra delay time to a stopped train that has a timed_stop component.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_unhitch(self: &amp;amp;amp;mut SimController, hitcher: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Remove the hitched state from a train. It will become an unspawned, unassigned train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simplesimcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimpleSimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimpleSimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A limited API version of SimController.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimpleSimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimpleSimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimpleSimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-taskeventtrain&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TaskEventTrain ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum TaskEventTrain {&lt;br /&gt;
    StopArrive,&lt;br /&gt;
    StopDepart,&lt;br /&gt;
    ShiftAssign,&lt;br /&gt;
    ShiftUnassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=557</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=557"/>
		<updated>2026-01-15T20:27:02Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used in game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration, integer division or arbitrary setting of pointers and references, and most data exposed to scripts is read-only, strictly enforced by the language. Any expression result which could result in an out of bounds or invalid memory access must be checked for validity, and the API design together with the type system enforces it.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
pub struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;SpeedTrap,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- VisMod? 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' ColonNAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Script&amp;lt;/code&amp;gt; (with restrictions)&lt;br /&gt;
&lt;br /&gt;
Structs extending game types for player extensions must be declared as &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt;. When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
To read struct objects from script code they must be looked up using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API. Therefore only functions provided with &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt; object (or a context object with contains &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt;) can look up these objects. But you can pass around &amp;lt;code&amp;gt;DB&amp;amp;amp;&amp;lt;/code&amp;gt; as a parameter without any lifetime restrictions, since it’s a purely read only API. This API also works for non-pub structs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= ctx.db.view&amp;amp;lt;Example&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    log(&amp;amp;quot;v = @&amp;amp;quot;, config.v);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;pub-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== pub structs ====&lt;br /&gt;
&lt;br /&gt;
As explained earlier, &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs are the user interface of your scripts. They are exposed in the UI as input forms, and their &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;s can give some control over this rendering. Conceptually they are owned by the player of the game as part of the game object database, by attaching them to a game model object in the database, not the script. Scripts do not have any capability to create, edit or delete objects of &amp;lt;code&amp;gt;pub struct&amp;lt;/code&amp;gt;s. It is always the player who decides when to create a new object of these structs by interacting in the UI. Scripts can then read, and only read, the content of these objects, by using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API presented earlier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs have a very powerful capability: they have limited support for forward schema evolution. This means that the script developer can add to, and reorder, fields in &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, and the game runtime will be able keep the contents of the other fields intact. This is very important to respect the input data by the player. If you rename &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs or their fields, or change their types, the player input data will be lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;non-pub-or-private-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Non-pub (or private) structs ====&lt;br /&gt;
&lt;br /&gt;
Non-&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, also called private structs, are conceptually owned by the script as a part of the simulation, not the player. Their contents are assumed to be a black box by the rest of the game. Scripts are allowed to create and modify objects of these structs during their execution, which are automatically deleted at the end of the simulation frame. It is also possible to attach these structs to existing game model objects to extend their lifetime beyond the current frame. In this case their lifetime becomes the same as the game object, and they can be retrieved in later frames for reading, deleted or overwritten as desired.&lt;br /&gt;
&lt;br /&gt;
Private structs ''do not support schema evolution''. Changing field types, field names, reordering of fields, even just adding new fields at the end, will always result in losing all existing attached objects of the given struct. Some operations like resetting the simulation will also erase attached objects, because they are considered simulation state, not player created objects.&lt;br /&gt;
&lt;br /&gt;
Private structs support dynamic memory allocation. All private struct definitions automatically create a &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; method for the struct:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct PrivData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let ro &amp;amp;amp;= ctx.db.view&amp;amp;lt;PrivData&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    let rw &amp;amp;amp;mut= ro.clone();&lt;br /&gt;
    rw.v = 100;&lt;br /&gt;
    let empty &amp;amp;amp;mut= PrivData::new();&lt;br /&gt;
    empty.v = 200;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The objects allocated by &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; are always deleted at the end of the current simulation frame. Their lifetime can be extended beyond the current frame by attaching them to a game object, like &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, so their lifetime becomes the same as the attached object. The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API has methods for attaching and erasing these object.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;host-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Host structs ====&lt;br /&gt;
&lt;br /&gt;
Many of the exposed game APIs are also based around structs. These structs do not follow any of the previous rules. Some have special capabilities, for example simple structs like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt; are ''value objects'': they can be copied and passed around like any &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; would. Some others are strictly locked down and serve as very little beyond a way to keep a pointer safe. In general, when working with game API structs, assume they are what would be called ''move only'' in C++. And NimbyScript has no move operator or semantics, so in essence assume they are immutable, immobile references, except when documented otherwise (like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As an aside, all script declared &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; or not) are also always ''move only'', and always “owned” by some external entity. This is why the APIs for their manipulation are always based on pointers and references, even for private structs. It is not possible to create plain, stack allocated values of script structs, or to use them as fields in structs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version:&lt;br /&gt;
&lt;br /&gt;
* Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
* Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums)&lt;br /&gt;
* For pub structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* For private structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In pub structs these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types. &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; will also display a small list editor. Keep in mind the correct type is &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;Vec&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- 'let' BindBody 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- 'let' BindBody ';'&lt;br /&gt;
BindBody    &amp;amp;lt;- NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' 'let' BindBody BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- ColonNAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere pointer types cannot be dereferenced, therefore cannot be used in dot expressions. The exception is the built-in function &amp;lt;code&amp;gt;is_valid(ptr): bool&amp;lt;/code&amp;gt;, which is usable with any pointer type.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;extensions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Extensions =&lt;br /&gt;
&lt;br /&gt;
Extending game database struct data with &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt; can also be used to extend the game code. The mechanism to do so is to first declare a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;ing a game database object (with or without fields). Then create a specifically named and parametrized function which will be called by the game under certain situations, for certain kinds of objects.&lt;br /&gt;
&lt;br /&gt;
All extension functions take a &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter which is a reference to the struct which it is method of, called &amp;lt;code&amp;gt;Example&amp;lt;/code&amp;gt; in the following sections. Replace it with your struct name. The rest of the parameters are fixed and must be reproduced exactly as-is.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
Event functions are called as part of the core simulation engine. They are meant to be focused in features and quick to execute. These functions might be called thousands of times per simulation frame, including multiple redundant times. Their capability to change the simulation behavior is usually very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_check&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_check ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails, or if another script call returns &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_lookahead&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_lookahead ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_lookahead(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    train_distance: f64,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalLookaheadResult&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; function at regular intervals for each signal 15km ahead of the train path. It is called for all signals, until one of these conditions hold: - One of the signals path checks as &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; - Another train is found - The train stop is found - 15km have been checked&lt;br /&gt;
&lt;br /&gt;
For both &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; signals, your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; will be called, and you can check the path find result in &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;, and the distance from the train in &amp;lt;code&amp;gt;train_distance&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; allows to set a maximum speed for the train, which goes into effect immediately. This works from any distance and past any amount of signals between the train and the caller signal. If multiple signals in the lookahead path return a &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt;, the slowest speed is picked. If no &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt; is set, or it is 0, the result is ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; default value is 0, which is considered invalid and will be ignored. To stop the train at the signal implement &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_change_path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_change_path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_change_path(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The current path check result of this signal for the passed train is passed as &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;. This already includes any results from &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_pass_by&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_pass_by ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_pass_by(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; function on the exact simulation frame a train passes by the exact point of the signal on the track.&lt;br /&gt;
&lt;br /&gt;
This function has no return result. Instead, since it has a predictably low call rate compared to the other events, it is the only event function with access to the powerful &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_marker_reserved&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_marker_reserved ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given marker signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; any time the reservation check algorithm is tracing a path which goes over the marker signal, on any direction, giving it the chance to report an arbitrary train as the reserver of that point on the track.&lt;br /&gt;
&lt;br /&gt;
This signal has a potential huge call rate, and for this reason it is given very little access to the APIs. The intention is that all the state required by this signal is calculated somewhere else and attached to the signal as a private struct object, or to some object reachable from it. Don’t worry about filtering for the “same train” cases, this is automatically done.&lt;br /&gt;
&lt;br /&gt;
If no reservation is desired, use the &amp;lt;code&amp;gt;empty&amp;lt;/code&amp;gt; global method available in all &amp;lt;code&amp;gt;ID&amp;amp;lt;Class&amp;amp;gt;&amp;lt;/code&amp;gt; types: &amp;lt;code&amp;gt;return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {}&lt;br /&gt;
struct Owner {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; {&lt;br /&gt;
    // some other, more full featured script function has attached Owner to this signal,&lt;br /&gt;
    // or not, so we need to check first&lt;br /&gt;
    if let owner &amp;amp;amp;= db.view&amp;amp;lt;Owner&amp;amp;gt;(signal) {&lt;br /&gt;
        if is_valid(db.view(owner.train_id)) {&lt;br /&gt;
            return owner.train_id;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_texture_state&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_texture_state ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_texture_state(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    clock_us: i64&lt;br /&gt;
): i64 { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment, when the game UI needs to query what is the current signal texture state index, it will call your &amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt;, with some potential caching to keep the call rate lower. In any case the call rate of this function is potentially very large when the user zooms out the map, so make sure to keep its code as efficient as possible. For this same reason it is given very little access to the APIs. &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; is the number of sim-microseconds since the current save was created, you use it with the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; functions to make animations.&lt;br /&gt;
&lt;br /&gt;
The return value indicates which signal texture state is to be used. If it’s -1 or lower, the default algorithm will be used to select the texture index. If it’s 0 or larger, it will select the texture in the same order as the &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; lines in the &amp;lt;code&amp;gt;SignalTextures&amp;lt;/code&amp;gt;. Larger values than the number of states will be clamped to the last state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_setup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_setup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_setup(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ss: &amp;amp;amp;mut ShiftSetup&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when an unassigned train decides to lookup a new shift to run, it will first call &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The parameter &amp;lt;code&amp;gt;ss&amp;lt;/code&amp;gt; is both an input and output parameter. It is initialized with the current, relevant data for the given train state, and &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; can then change it, to influence which shifts will be considered by the shift selection algorithm. It can change the train position used for matching, the time used for matching, and disable the check for reservations. For matched shifts which do not correspond to the current train position, the Extrapolator system will automatically pathfind a temporary milestone for the train, like other path-changing features.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_allow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_allow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_allow(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    run: &amp;amp;amp;Run,&lt;br /&gt;
    stop_idx: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    pose: &amp;amp;amp;Pose&lt;br /&gt;
): ShiftAllow { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when the shift selection algorithm fins a valid shift for the given train, it will call &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; with all the relevant data. The return of the function can then allow or deny the shift. If the shift is denied, the algorithm will resume immediately, trying other shifts&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are independent from each other, and can be used in any combination.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;linestop-event_line_stop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Line::Stop event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestStop extend Line::Stop {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestStop::event_line_stop(&lt;br /&gt;
    self: &amp;amp;amp;TestStop,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == LineStopEvent::Arrive {&lt;br /&gt;
        log(&amp;amp;quot;@ arrives @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ departs @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given line stop in the line editor. From that moment, when any train arrives or departs said line stop, &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LineStopEvent::Depart&amp;lt;/code&amp;gt; to distinguish between arrival and departure. Waypoints are only called for &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt;. Shift-less trains are also called.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;shift-event_shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Shift event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestShift extend Shift {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestShift::event_shift(&lt;br /&gt;
    self: &amp;amp;amp;TestShift,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == ShiftEvent::Assign {&lt;br /&gt;
        log(&amp;amp;quot;@ assigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ unassigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given schedule shift in the line editor. From that moment, when any train is assigned to the shift, or becomes unassigned from the shift, &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;ShiftEvent::Assign&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ShiftEvent::Unassign&amp;lt;/code&amp;gt; to distinguish between assignation and unassignation. The &amp;lt;code&amp;gt;Assign&amp;lt;/code&amp;gt; event is called just after &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been set up, so it already has all the shift and run information. The &amp;lt;code&amp;gt;Unassign&amp;lt;/code&amp;gt; event is called just before &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been cleared of all shift and run information so the script has access to as much information as possible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;global-events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Global events ==&lt;br /&gt;
&lt;br /&gt;
Like event functions of struct extensions, global events are called as part of the core simulation engine when a specific event occurs, but they are not associated to any struct. Instead they are public top level functions with the signature given in this document. Global event functions are always called if they exist in a script and the event occurs.&lt;br /&gt;
&lt;br /&gt;
=== global_event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn global_event_line_stop(&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    log(&amp;amp;quot;global_event_line_stop: @ on line @&amp;amp;quot;, train, line);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Arguments and conditions are identical to &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt;, except there is no &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter.&lt;br /&gt;
&lt;br /&gt;
=== global_event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn global_event_shift(&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    log(&amp;amp;quot;global_event_shift: @ on sched @&amp;amp;quot;, train, sched);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Arguments and conditions are identical to &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt;, except there is no &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;controllers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Controllers ==&lt;br /&gt;
&lt;br /&gt;
Controller functions are called at a low frame rate compared to the overall simulation, with an (unchangeable) rate of once in 6 sim-seconds. They do not need any specific event or trigger to run, other than their enforced timer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-control_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train control_train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct HateDepots extend Train {}&lt;br /&gt;
pub fn HateDepots::control_train(&lt;br /&gt;
    self: &amp;amp;amp;HateDepots,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    // train is already removed from the tracks, don't interfere with potential attempts at shift assignation&lt;br /&gt;
    if !is_valid(motion.presence.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is running a schedule, don't interfere&lt;br /&gt;
    if is_valid(motion.schedule_dispatch.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is present, but it is not running a schedule, so despawn it&lt;br /&gt;
    sc.queue_train_intervention(train);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The train motion engine will call train controllers in the multithreaded phase, as part of the regular train motion extrapolator, after all the C++ code is done for a frame for a particular train, but before any queued commands are executed. Command execution will only happen after all train controllers for a given frame are done. In other words, train controllers queue up work to be executed by the sim. They never directly change the sim in any way, allowing train controller execution to be fully parallel.&lt;br /&gt;
&lt;br /&gt;
After all controllers are run, and all their non-task commands are executed, and then tasks are executed. Read more about tasks later on. Any tasks with a deadline which expired in this frame a run at this time too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontroller-command-queue&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== SimController command queue ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; object implements an API to control the simulation, including modification of some parameters and behaviors. It is also responsible for attaching and erasing private struct data from game objects, on behalf of scripts. The execution of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; is based on a command queue. Every call queues a command and returns immediately to the script code, without making any changes to the game state. Therefore the game state never changes while the script code is running.&lt;br /&gt;
&lt;br /&gt;
Commands queued from events and &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt; are executed asynchronously, there is no guaranteed order of execution! You must prepare your code and data for this design. For stand alone tasks scripts commands are executed in order and in isolation. You can queue up tasks from event and control scripts when you need to guarantee data consistency beyond “pick a random winner”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_intervention&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_intervention ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks, releases its schedule shift (if any), and deletes and refunds its pax (if any). No other cost other than pax refunds is issued. This function can be used as a general “despawn the train” feature, not just for exceptional circumstances.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_warp&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_warp ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks and repositions it at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, re-pathing it to its currently scheduled destination (if any), and setting its speed to 0. This is basically a train wormhole. The train keeps its shift and pax, if any.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_drive_to&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_drive_to ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Re-paths the train path to end at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, without any changes to its shift or pax (if any). It is possible for any future &amp;lt;code&amp;gt;queue_train_drive_to&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; to reset this path at any point, losing the destination. “Queue” here is used as part of the SimController API semantics, it does not mean the train keeps a queue of positions to reach. If the path is not interrupted and the train reaches &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; it will re-path itself towards its current scheduled stop, if it has any, or brake to a stop if unassigned. If &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; was also in the stop area set for its current scheduled stop it will also brake to stop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_attach&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_attach ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the attachment of the &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;existing.clone()&amp;lt;/code&amp;gt;) to the &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt;, which must be of one of the following types: &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attached objects can be accessed with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt; at some point in the future. If called from a controller function, the attached object will be accessible after all controller functions are done for a given frame. If called from a task, he attached object will be accessible immediately after the task returns, and before any other task is executed. In other words, tasks are transaction-like, in the sense they view an immutable snapshot of the game state, and any changes they queue are executed before any other task, and then visible from these other tasks.&lt;br /&gt;
&lt;br /&gt;
Attaching an object of a given private struct type when it already exists attached to a &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt; will overwrite it. This is how private data is updated from scripting: by using &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; to copy any existing data, modifying the copy, then calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; to replace the existing data. Therefore it is a good idea to keep your private structs small. Only one instance of a given private struct type can be attached to any particular model object, but you can attach as many different private struct types as you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_erase&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_erase ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the erasure of &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt;, which must obtained using with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt;. Trying to erase temporary objects (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;existing.clone()&amp;lt;/code&amp;gt;) is ignored. The execution of the queued erase commands is analog to the &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; case. In particular a sequences of attach and erase queued from controllers will produce undefined results (impossible to predict which attach and/or erase wins). For example multiple attach from a controller for the same model_obj and private struct type will implicitly pick a singular “winner” attach, but the script does not have any control over which one. Sequences of attach and erase queued from tasks are strictly ordered and isolated, so they produce consistent results, in the same order they were queued in the task script, without any concurrent changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task-and-simcontrollerqueue_task_at&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task and SimController::queue_task_at ===&lt;br /&gt;
&lt;br /&gt;
See [[#Control%20tasks|control tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task_event_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task_event_train ===&lt;br /&gt;
&lt;br /&gt;
See [[#Event%20tasks|event tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;control-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Control tasks ==&lt;br /&gt;
&lt;br /&gt;
Control tasks are a very special kind of command which allows scripts to dynamically queue “future work”, with privileged access to the sim. Scripts with access to &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; can call this function to queue up a task for future script execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; must be of a private struct type which implements &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example { ... }&lt;br /&gt;
pub fn Example::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
For example, a train controller script could decide it needs to delay some decision into a task for data consistency reasons (other controllers are running at the same time), and delegate into a task rather than directly calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ControlTrain extend Train { ... }&lt;br /&gt;
pub fn ControlTrain::control_train(&lt;br /&gt;
    self: &amp;amp;amp;ControlTrain,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    task.train_id = train.id;&lt;br /&gt;
    task.v = some_data_from_somewhere;&lt;br /&gt;
    task.prio = 42; // or something smarter, like from ControlTrain, other objects, etc.&lt;br /&gt;
    sc.queue_task(task);&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
struct Task {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
struct SomeData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
pub fn Task::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    let train &amp;amp;amp;= ctx.db.view(self.train_id) else { return; }&lt;br /&gt;
    if let existing &amp;amp;amp;= ctx.db.view&amp;amp;lt;SomeData&amp;amp;gt;(train) {&lt;br /&gt;
        if existing.prio &amp;amp;gt;= self.prio {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    let data = SomeData::new();&lt;br /&gt;
    data.v = self.v;&lt;br /&gt;
    data.prio = self.prio;&lt;br /&gt;
    sc.queue_attach(train, data);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the previous example, maybe &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; will be called multiple times because multiple &amp;lt;code&amp;gt;ControlTrain::control_train()&amp;lt;/code&amp;gt; instances queued objects of &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;, but each execution will be single threaded, and all its queued &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; commands will be executed just after the call is done and before any other &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; call (for &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; or any other struct type), therefore the algorithm to pick a winner based on an explicit priority works.&lt;br /&gt;
&lt;br /&gt;
As mentioned, task execution is single threaded. The game does not feature a real concurrent database, instead all concurrent access is bespoke and very carefully designed to avoid deadlocks and inconsistencies (this is much faster than a general purpose concurrent database). Scripts also run in this parallel system, but their access to the game state is carefully restricted as explained earlier. But in the end, scripts also need to modify data, and do so in a consistent way. Tasks solve this issue, but do so in the most pessimistic possible way, by being single threaded. Therefore script developers should use them in moderation. Consider the “random winner” semantics of control script queuing first, which are completely free performance wise, before deciding you need a task. It is often the case a concurrent problem reduces to “pick 0 or 1 winners, any winner, but never 2 or more” and the default queue semantics already provide that guarantee for attaching a specific model/private pair.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; is provided with &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt;, therefore it can queue tasks itself. But unlike controller queuing tasks, which are guaranteed to run on the same frame, tasks queued from tasks are guaranteed to ''not'' run on the same frame, on purpose. They are deliberately stored away and forced a delay of 6 sim-seconds. This is to avoid misuse of tasks, and infinite looping.&lt;br /&gt;
&lt;br /&gt;
This behavior might even be desirable in certain scripts, for example if you are developing some stateful signal system and you need some kind of “cleanup” task that makes sure some signal being owned by some train is still the focus of said train. You can deliberately queue tasks for future simulation frames with &amp;lt;code&amp;gt;queue_task_at&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;deadline&amp;lt;/code&amp;gt; is expressed as microseconds since the start of the current save world. You can obtain the current simulation frame &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; value with &amp;lt;code&amp;gt;Extrapolator::clock_us()&amp;lt;/code&amp;gt;, like in this example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;    // schedule task to run 10 sim-s from now&lt;br /&gt;
    sc.queue_task_at(task, ctx.extrapolator.clock_us() + 10000000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;event-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Event tasks ==&lt;br /&gt;
&lt;br /&gt;
Event tasks are a lightweight version of tasks which run when triggered by certain events. Unlike control tasks, event tasks do not have unlimited access to the sim. Instead the run under an &amp;lt;code&amp;gt;EventCtx&amp;lt;/code&amp;gt; like pub struct events, and run multithreaded, at the same time as the C++ code. Unlike the regular &amp;lt;code&amp;gt;event_*&amp;lt;/code&amp;gt; methods, event tasks are queued for execution by script code, not by UI player commands. The design idea of these tasks is to offer a more focused and efficient execution model than &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt;: they are executed immediately once the relevant event happens, in multithreaded context, rather than require passive polling which might even miss certain events and force execution of single thread code.&lt;br /&gt;
&lt;br /&gt;
Any function with a &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; parameter can queue an even task like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Task {...}&lt;br /&gt;
fn f(..., train: &amp;amp;amp;Train, sc: &amp;amp;amp;mut SimController) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    sc.queue_task_event_train(task, train, TaskEventTrain::StopDepart);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
On the next stop departure of the train the &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt; method will be called:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn Task::task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: TaskEventTrain,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == TaskEventTrain::StopDepart {&lt;br /&gt;
        log(&amp;amp;quot;@ departs&amp;amp;quot;, train);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Like control tasks, event tasks encapsulate a single call. If a series of calls are desired, the task can requeue itself by calling &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt;. Event tasks are limited to a maximum of 1 for every possible train-struct-event combination, to avoid leaks. Trying to queue again the same train-struct-event combination will overwrite any existing task. Only the train and motion are provided as parameters. The code can then drill into motion to extract any required information, like shift or line.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-controlctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ControlCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ControlCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    sim: &amp;amp;amp;Sim,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim controller scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects, and associated script stuct objects.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::track_pos_project(self: &amp;amp;amp;DB, pos: &amp;amp;amp;Pos, distance: f64): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return a track position separated by ‘distance’ meters from ‘pos’, in the direction of ‘pos’. If distance is negative it will be in the opposite direction. Can only follow the main track. Merges and dead ends will return a Pos a shorter distance away. Signals are ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view_self(self: &amp;amp;amp;DB): &amp;amp;amp;Script&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-eventctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type EventCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct EventCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim event handler scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line::Stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line::Stop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    cars_config: i32,&lt;br /&gt;
    dynamics: Train::Dynamics,&lt;br /&gt;
    hitched_by: Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    station_stop: std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;,&lt;br /&gt;
    run_stop: std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
    run_dispatch: std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;,&lt;br /&gt;
    hitch: std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motioncachedhitcher&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::CachedHitcher ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::CachedHitcher {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionhitch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Hitch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Hitch {&lt;br /&gt;
    driver_train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    flip: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Train is being hitched by a driver train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
    flip: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionrundispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::RunDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::RunDispatch {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a line run.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Motion::RunDispatch::current_stop(self: &amp;amp;amp;Motion::RunDispatch, line: &amp;amp;amp;Line): *Line::Stop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionstationstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::StationStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::StationStop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Schedule::view(self: &amp;amp;amp;Schedule, shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;): *Shift&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns a pointer to the shift, if it’s contained in this schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-script&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Script ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Script {&lt;br /&gt;
    id: ID&amp;amp;lt;Script&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Shift {&lt;br /&gt;
    id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::kind(self: &amp;amp;amp;Signal): mut SignalKind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the signal kind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-traindynamics&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train::Dynamics ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train::Dynamics {&lt;br /&gt;
    max_speed: f32,&lt;br /&gt;
    max_acceleration: f32,&lt;br /&gt;
    max_regular_braking: f32,&lt;br /&gt;
    max_emergency_braking: f32,&lt;br /&gt;
    max_tractive_effort: f32,&lt;br /&gt;
    total_power: f32,&lt;br /&gt;
    empty_mass: f32,&lt;br /&gt;
    length: f32,&lt;br /&gt;
    max_pax: i32,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vec&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;lt;Motion::CachedHitcher&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Hitch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;): *Motion::Hitch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStationEvent&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;&lt;br /&gt;
): *Motion::StationStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Script&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Shift&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Shift&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Shift&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciterator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;lt;Motion::CachedHitcher&amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator::next(&lt;br /&gt;
    self: &amp;amp;amp;mut Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator&lt;br /&gt;
): *Motion::CachedHitcher&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    idx: i64&lt;br /&gt;
): *Motion::CachedHitcher&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::clock_us(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current microseconds since the creation of this saved game. This is used as the timing root of the simulation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second since 1970-01-01:00:00:00.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_occupation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_reservation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying or reserving the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_occupying(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_reserving(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying or reserving the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
Probe a track position for train reservations and occupations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Seconds since 1970-01-01:00:00:00 for Monday 00:00:00 of the current week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestopevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type LineStopEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum LineStopEvent {&lt;br /&gt;
    Arrive,&lt;br /&gt;
    Depart,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
Advance the iterator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftallow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftAllow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftAllow {&lt;br /&gt;
    Allow,&lt;br /&gt;
    Deny,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftEvent {&lt;br /&gt;
    Assign,&lt;br /&gt;
    Unassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftsetup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftSetup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ShiftSetup {&lt;br /&gt;
    skip: bool,&lt;br /&gt;
    match_pos: bool,&lt;br /&gt;
    check_occupation: bool,&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores the context of a train shift lookup.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function wants to change the train path, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signallookaheadresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalLookaheadResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalLookaheadResult {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores extra information associated with the result of the signal lookahead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-sim&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Sim ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Sim {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of the simulation state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Sim::view&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Sim, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A proxy mutable API to the simulation engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    ev: TaskEventTrain&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_hitch(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    driver: &amp;amp;amp;Train,&lt;br /&gt;
    hitcher: &amp;amp;amp;Train,&lt;br /&gt;
    order: i64,&lt;br /&gt;
    flip: bool&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hitch a train to a driver train. The hitched train is emptied of pax and removed from the sim, while its cars are appended to the driver. The order parameter (from -1000 to 1000) determines the hitched train cars position: the driver train is always order 0, so negative values will put the hitch in front of the driver, and positive values behind it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(self: &amp;amp;amp;mut SimController, train: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_run_line(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    arrival_offset_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_configuration(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    config: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_presence_flip(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    flip: bool&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_stop_delay(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    delay_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add extra delay time to a stopped train that has a timed_stop component.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_unhitch(self: &amp;amp;amp;mut SimController, hitcher: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Remove the hitched state from a train. It will become an unspawned, unassigned train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-taskeventtrain&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TaskEventTrain ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum TaskEventTrain {&lt;br /&gt;
    StopArrive,&lt;br /&gt;
    StopDepart,&lt;br /&gt;
    ShiftAssign,&lt;br /&gt;
    ShiftUnassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=556</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=556"/>
		<updated>2026-01-07T11:45:00Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used in game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration, integer division or arbitrary setting of pointers and references, and most data exposed to scripts is read-only, strictly enforced by the language. Any expression result which could result in an out of bounds or invalid memory access must be checked for validity, and the API design together with the type system enforces it.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
pub struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;SpeedTrap,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- VisMod? 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' ColonNAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Script&amp;lt;/code&amp;gt; (with restrictions)&lt;br /&gt;
&lt;br /&gt;
Structs extending game types for player extensions must be declared as &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt;. When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
To read struct objects from script code they must be looked up using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API. Therefore only functions provided with &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt; object (or a context object with contains &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt;) can look up these objects. But you can pass around &amp;lt;code&amp;gt;DB&amp;amp;amp;&amp;lt;/code&amp;gt; as a parameter without any lifetime restrictions, since it’s a purely read only API. This API also works for non-pub structs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= ctx.db.view&amp;amp;lt;Example&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    log(&amp;amp;quot;v = @&amp;amp;quot;, config.v);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;pub-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== pub structs ====&lt;br /&gt;
&lt;br /&gt;
As explained earlier, &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs are the user interface of your scripts. They are exposed in the UI as input forms, and their &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;s can give some control over this rendering. Conceptually they are owned by the player of the game as part of the game object database, by attaching them to a game model object in the database, not the script. Scripts do not have any capability to create, edit or delete objects of &amp;lt;code&amp;gt;pub struct&amp;lt;/code&amp;gt;s. It is always the player who decides when to create a new object of these structs by interacting in the UI. Scripts can then read, and only read, the content of these objects, by using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API presented earlier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs have a very powerful capability: they have limited support for forward schema evolution. This means that the script developer can add to, and reorder, fields in &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, and the game runtime will be able keep the contents of the other fields intact. This is very important to respect the input data by the player. If you rename &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs or their fields, or change their types, the player input data will be lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;non-pub-or-private-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Non-pub (or private) structs ====&lt;br /&gt;
&lt;br /&gt;
Non-&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, also called private structs, are conceptually owned by the script as a part of the simulation, not the player. Their contents are assumed to be a black box by the rest of the game. Scripts are allowed to create and modify objects of these structs during their execution, which are automatically deleted at the end of the simulation frame. It is also possible to attach these structs to existing game model objects to extend their lifetime beyond the current frame. In this case their lifetime becomes the same as the game object, and they can be retrieved in later frames for reading, deleted or overwritten as desired.&lt;br /&gt;
&lt;br /&gt;
Private structs ''do not support schema evolution''. Changing field types, field names, reordering of fields, even just adding new fields at the end, will always result in losing all existing attached objects of the given struct. Some operations like resetting the simulation will also erase attached objects, because they are considered simulation state, not player created objects.&lt;br /&gt;
&lt;br /&gt;
Private structs support dynamic memory allocation. All private struct definitions automatically create a &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; method for the struct:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct PrivData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let ro &amp;amp;amp;= ctx.db.view&amp;amp;lt;PrivData&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    let rw &amp;amp;amp;mut= ro.clone();&lt;br /&gt;
    rw.v = 100;&lt;br /&gt;
    let empty &amp;amp;amp;mut= PrivData::new();&lt;br /&gt;
    empty.v = 200;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The objects allocated by &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; are always deleted at the end of the current simulation frame. Their lifetime can be extended beyond the current frame by attaching them to a game object, like &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, so their lifetime becomes the same as the attached object. The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API has methods for attaching and erasing these object.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;host-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Host structs ====&lt;br /&gt;
&lt;br /&gt;
Many of the exposed game APIs are also based around structs. These structs do not follow any of the previous rules. Some have special capabilities, for example simple structs like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt; are ''value objects'': they can be copied and passed around like any &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; would. Some others are strictly locked down and serve as very little beyond a way to keep a pointer safe. In general, when working with game API structs, assume they are what would be called ''move only'' in C++. And NimbyScript has no move operator or semantics, so in essence assume they are immutable, immobile references, except when documented otherwise (like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As an aside, all script declared &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; or not) are also always ''move only'', and always “owned” by some external entity. This is why the APIs for their manipulation are always based on pointers and references, even for private structs. It is not possible to create plain, stack allocated values of script structs, or to use them as fields in structs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version:&lt;br /&gt;
&lt;br /&gt;
* Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
* Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums)&lt;br /&gt;
* For pub structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* For private structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In pub structs these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types. &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; will also display a small list editor. Keep in mind the correct type is &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;Vec&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- 'let' BindBody 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- 'let' BindBody ';'&lt;br /&gt;
BindBody    &amp;amp;lt;- NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' 'let' BindBody BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- ColonNAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere pointer types cannot be dereferenced, therefore cannot be used in dot expressions. The exception is the built-in function &amp;lt;code&amp;gt;is_valid(ptr): bool&amp;lt;/code&amp;gt;, which is usable with any pointer type.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;extensions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Extensions =&lt;br /&gt;
&lt;br /&gt;
Extending game database struct data with &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt; can also be used to extend the game code. The mechanism to do so is to first declare a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;ing a game database object (with or without fields). Then create a specifically named and parametrized function which will be called by the game under certain situations, for certain kinds of objects.&lt;br /&gt;
&lt;br /&gt;
All extension functions take a &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter which is a reference to the struct which it is method of, called &amp;lt;code&amp;gt;Example&amp;lt;/code&amp;gt; in the following sections. Replace it with your struct name. The rest of the parameters are fixed and must be reproduced exactly as-is.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
Event functions are called as part of the core simulation engine. They are meant to be focused in features and quick to execute. These functions might be called thousands of times per simulation frame, including multiple redundant times. Their capability to change the simulation behavior is usually very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_check&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_check ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails, or if another script call returns &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_lookahead&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_lookahead ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_lookahead(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    train_distance: f64,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalLookaheadResult&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; function at regular intervals for each signal 15km ahead of the train path. It is called for all signals, until one of these conditions hold: - One of the signals path checks as &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; - Another train is found - The train stop is found - 15km have been checked&lt;br /&gt;
&lt;br /&gt;
For both &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; signals, your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; will be called, and you can check the path find result in &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;, and the distance from the train in &amp;lt;code&amp;gt;train_distance&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; allows to set a maximum speed for the train, which goes into effect immediately. This works from any distance and past any amount of signals between the train and the caller signal. If multiple signals in the lookahead path return a &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt;, the slowest speed is picked. If no &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt; is set, or it is 0, the result is ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; default value is 0, which is considered invalid and will be ignored. To stop the train at the signal implement &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_change_path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_change_path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_change_path(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The current path check result of this signal for the passed train is passed as &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;. This already includes any results from &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_pass_by&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_pass_by ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_pass_by(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; function on the exact simulation frame a train passes by the exact point of the signal on the track.&lt;br /&gt;
&lt;br /&gt;
This function has no return result. Instead, since it has a predictably low call rate compared to the other events, it is the only event function with access to the powerful &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_marker_reserved&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_marker_reserved ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given marker signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; any time the reservation check algorithm is tracing a path which goes over the marker signal, on any direction, giving it the chance to report an arbitrary train as the reserver of that point on the track.&lt;br /&gt;
&lt;br /&gt;
This signal has a potential huge call rate, and for this reason it is given very little access to the APIs. The intention is that all the state required by this signal is calculated somewhere else and attached to the signal as a private struct object, or to some object reachable from it. Don’t worry about filtering for the “same train” cases, this is automatically done.&lt;br /&gt;
&lt;br /&gt;
If no reservation is desired, use the &amp;lt;code&amp;gt;empty&amp;lt;/code&amp;gt; global method available in all &amp;lt;code&amp;gt;ID&amp;amp;lt;Class&amp;amp;gt;&amp;lt;/code&amp;gt; types: &amp;lt;code&amp;gt;return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {}&lt;br /&gt;
struct Owner {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; {&lt;br /&gt;
    // some other, more full featured script function has attached Owner to this signal,&lt;br /&gt;
    // or not, so we need to check first&lt;br /&gt;
    if let owner &amp;amp;amp;= db.view&amp;amp;lt;Owner&amp;amp;gt;(signal) {&lt;br /&gt;
        if is_valid(db.view(owner.train_id)) {&lt;br /&gt;
            return owner.train_id;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_texture_state&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_texture_state ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_texture_state(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): i64 { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment, when the game UI needs to query what is the current signal texture state index, it will call your &amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt;, with some potential caching to keep the call rate lower. In any case the call rate of this function is potentially very large when the user zooms out the map, so make sure to keep its code as efficient as possible. For this same reason it is given very little access to the APIs.&lt;br /&gt;
&lt;br /&gt;
The return value indicates which signal texture state is to be used. If it’s -1 or lower, the default algorithm will be used to select the texture index. If it’s 0 or larger, it will select the texture in the same order as the &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; lines in the &amp;lt;code&amp;gt;SignalTextures&amp;lt;/code&amp;gt;. Larger values than the number of states will be clamped to the last state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_setup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_setup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_setup(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ss: &amp;amp;amp;mut ShiftSetup&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when an unassigned train decides to lookup a new shift to run, it will first call &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The parameter &amp;lt;code&amp;gt;ss&amp;lt;/code&amp;gt; is both an input and output parameter. It is initialized with the current, relevant data for the given train state, and &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; can then change it, to influence which shifts will be considered by the shift selection algorithm. It can change the train position used for matching, the time used for matching, and disable the check for reservations. For matched shifts which do not correspond to the current train position, the Extrapolator system will automatically pathfind a temporary milestone for the train, like other path-changing features.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_allow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_allow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_allow(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    run: &amp;amp;amp;Run,&lt;br /&gt;
    stop_idx: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    pose: &amp;amp;amp;Pose&lt;br /&gt;
): ShiftAllow { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when the shift selection algorithm fins a valid shift for the given train, it will call &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; with all the relevant data. The return of the function can then allow or deny the shift. If the shift is denied, the algorithm will resume immediately, trying other shifts&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are independent from each other, and can be used in any combination.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;linestop-event_line_stop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Line::Stop event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestStop extend Line::Stop {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestStop::event_line_stop(&lt;br /&gt;
    self: &amp;amp;amp;TestStop,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == LineStopEvent::Arrive {&lt;br /&gt;
        log(&amp;amp;quot;@ arrives @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ departs @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given line stop in the line editor. From that moment, when any train arrives or departs said line stop, &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LineStopEvent::Depart&amp;lt;/code&amp;gt; to distinguish between arrival and departure. Waypoints are only called for &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt;. Shift-less trains are also called.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;shift-event_shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Shift event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestShift extend Shift {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestShift::event_shift(&lt;br /&gt;
    self: &amp;amp;amp;TestShift,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == ShiftEvent::Assign {&lt;br /&gt;
        log(&amp;amp;quot;@ assigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ unassigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given schedule shift in the line editor. From that moment, when any train is assigned to the shift, or becomes unassigned from the shift, &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;ShiftEvent::Assign&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ShiftEvent::Unassign&amp;lt;/code&amp;gt; to distinguish between assignation and unassignation. The &amp;lt;code&amp;gt;Assign&amp;lt;/code&amp;gt; event is called just after &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been set up, so it already has all the shift and run information. The &amp;lt;code&amp;gt;Unassign&amp;lt;/code&amp;gt; event is called just before &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been cleared of all shift and run information so the script has access to as much information as possible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;global-events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Global events ==&lt;br /&gt;
&lt;br /&gt;
Like event functions of struct extensions, global events are called as part of the core simulation engine when a specific event occurs, but they are not associated to any struct. Instead they are public top level functions with the signature given in this document. Global event functions are always called if they exist in a script and the event occurs.&lt;br /&gt;
&lt;br /&gt;
=== global_event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn global_event_line_stop(&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    log(&amp;amp;quot;global_event_line_stop: @ on line @&amp;amp;quot;, train, line);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Arguments and conditions are identical to &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt;, except there is no &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter.&lt;br /&gt;
&lt;br /&gt;
=== global_event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn global_event_shift(&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    log(&amp;amp;quot;global_event_shift: @ on sched @&amp;amp;quot;, train, sched);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Arguments and conditions are identical to &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt;, except there is no &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;controllers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Controllers ==&lt;br /&gt;
&lt;br /&gt;
Controller functions are called at a low frame rate compared to the overall simulation, with an (unchangeable) rate of once in 6 sim-seconds. They do not need any specific event or trigger to run, other than their enforced timer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-control_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train control_train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct HateDepots extend Train {}&lt;br /&gt;
pub fn HateDepots::control_train(&lt;br /&gt;
    self: &amp;amp;amp;HateDepots,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    // train is already removed from the tracks, don't interfere with potential attempts at shift assignation&lt;br /&gt;
    if !is_valid(motion.presence.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is running a schedule, don't interfere&lt;br /&gt;
    if is_valid(motion.schedule_dispatch.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is present, but it is not running a schedule, so despawn it&lt;br /&gt;
    sc.queue_train_intervention(train);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The train motion engine will call train controllers in the multithreaded phase, as part of the regular train motion extrapolator, after all the C++ code is done for a frame for a particular train, but before any queued commands are executed. Command execution will only happen after all train controllers for a given frame are done. In other words, train controllers queue up work to be executed by the sim. They never directly change the sim in any way, allowing train controller execution to be fully parallel.&lt;br /&gt;
&lt;br /&gt;
After all controllers are run, and all their non-task commands are executed, and then tasks are executed. Read more about tasks later on. Any tasks with a deadline which expired in this frame a run at this time too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontroller-command-queue&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== SimController command queue ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; object implements an API to control the simulation, including modification of some parameters and behaviors. It is also responsible for attaching and erasing private struct data from game objects, on behalf of scripts. The execution of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; is based on a command queue. Every call queues a command and returns immediately to the script code, without making any changes to the game state. Therefore the game state never changes while the script code is running.&lt;br /&gt;
&lt;br /&gt;
Commands queued from events and &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt; are executed asynchronously, there is no guaranteed order of execution! You must prepare your code and data for this design. For stand alone tasks scripts commands are executed in order and in isolation. You can queue up tasks from event and control scripts when you need to guarantee data consistency beyond “pick a random winner”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_intervention&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_intervention ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks, releases its schedule shift (if any), and deletes and refunds its pax (if any). No other cost other than pax refunds is issued. This function can be used as a general “despawn the train” feature, not just for exceptional circumstances.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_warp&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_warp ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks and repositions it at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, re-pathing it to its currently scheduled destination (if any), and setting its speed to 0. This is basically a train wormhole. The train keeps its shift and pax, if any.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_drive_to&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_drive_to ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Re-paths the train path to end at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, without any changes to its shift or pax (if any). It is possible for any future &amp;lt;code&amp;gt;queue_train_drive_to&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; to reset this path at any point, losing the destination. “Queue” here is used as part of the SimController API semantics, it does not mean the train keeps a queue of positions to reach. If the path is not interrupted and the train reaches &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; it will re-path itself towards its current scheduled stop, if it has any, or brake to a stop if unassigned. If &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; was also in the stop area set for its current scheduled stop it will also brake to stop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_attach&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_attach ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the attachment of the &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;existing.clone()&amp;lt;/code&amp;gt;) to the &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt;, which must be of one of the following types: &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attached objects can be accessed with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt; at some point in the future. If called from a controller function, the attached object will be accessible after all controller functions are done for a given frame. If called from a task, he attached object will be accessible immediately after the task returns, and before any other task is executed. In other words, tasks are transaction-like, in the sense they view an immutable snapshot of the game state, and any changes they queue are executed before any other task, and then visible from these other tasks.&lt;br /&gt;
&lt;br /&gt;
Attaching an object of a given private struct type when it already exists attached to a &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt; will overwrite it. This is how private data is updated from scripting: by using &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; to copy any existing data, modifying the copy, then calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; to replace the existing data. Therefore it is a good idea to keep your private structs small. Only one instance of a given private struct type can be attached to any particular model object, but you can attach as many different private struct types as you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_erase&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_erase ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the erasure of &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt;, which must obtained using with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt;. Trying to erase temporary objects (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;existing.clone()&amp;lt;/code&amp;gt;) is ignored. The execution of the queued erase commands is analog to the &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; case. In particular a sequences of attach and erase queued from controllers will produce undefined results (impossible to predict which attach and/or erase wins). For example multiple attach from a controller for the same model_obj and private struct type will implicitly pick a singular “winner” attach, but the script does not have any control over which one. Sequences of attach and erase queued from tasks are strictly ordered and isolated, so they produce consistent results, in the same order they were queued in the task script, without any concurrent changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task-and-simcontrollerqueue_task_at&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task and SimController::queue_task_at ===&lt;br /&gt;
&lt;br /&gt;
See [[#Control%20tasks|control tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task_event_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task_event_train ===&lt;br /&gt;
&lt;br /&gt;
See [[#Event%20tasks|event tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;control-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Control tasks ==&lt;br /&gt;
&lt;br /&gt;
Control tasks are a very special kind of command which allows scripts to dynamically queue “future work”, with privileged access to the sim. Scripts with access to &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; can call this function to queue up a task for future script execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; must be of a private struct type which implements &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example { ... }&lt;br /&gt;
pub fn Example::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
For example, a train controller script could decide it needs to delay some decision into a task for data consistency reasons (other controllers are running at the same time), and delegate into a task rather than directly calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ControlTrain extend Train { ... }&lt;br /&gt;
pub fn ControlTrain::control_train(&lt;br /&gt;
    self: &amp;amp;amp;ControlTrain,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    task.train_id = train.id;&lt;br /&gt;
    task.v = some_data_from_somewhere;&lt;br /&gt;
    task.prio = 42; // or something smarter, like from ControlTrain, other objects, etc.&lt;br /&gt;
    sc.queue_task(task);&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
struct Task {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
struct SomeData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
pub fn Task::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    let train &amp;amp;amp;= ctx.db.view(self.train_id) else { return; }&lt;br /&gt;
    if let existing &amp;amp;amp;= ctx.db.view&amp;amp;lt;SomeData&amp;amp;gt;(train) {&lt;br /&gt;
        if existing.prio &amp;amp;gt;= self.prio {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    let data = SomeData::new();&lt;br /&gt;
    data.v = self.v;&lt;br /&gt;
    data.prio = self.prio;&lt;br /&gt;
    sc.queue_attach(train, data);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the previous example, maybe &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; will be called multiple times because multiple &amp;lt;code&amp;gt;ControlTrain::control_train()&amp;lt;/code&amp;gt; instances queued objects of &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;, but each execution will be single threaded, and all its queued &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; commands will be executed just after the call is done and before any other &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; call (for &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; or any other struct type), therefore the algorithm to pick a winner based on an explicit priority works.&lt;br /&gt;
&lt;br /&gt;
As mentioned, task execution is single threaded. The game does not feature a real concurrent database, instead all concurrent access is bespoke and very carefully designed to avoid deadlocks and inconsistencies (this is much faster than a general purpose concurrent database). Scripts also run in this parallel system, but their access to the game state is carefully restricted as explained earlier. But in the end, scripts also need to modify data, and do so in a consistent way. Tasks solve this issue, but do so in the most pessimistic possible way, by being single threaded. Therefore script developers should use them in moderation. Consider the “random winner” semantics of control script queuing first, which are completely free performance wise, before deciding you need a task. It is often the case a concurrent problem reduces to “pick 0 or 1 winners, any winner, but never 2 or more” and the default queue semantics already provide that guarantee for attaching a specific model/private pair.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; is provided with &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt;, therefore it can queue tasks itself. But unlike controller queuing tasks, which are guaranteed to run on the same frame, tasks queued from tasks are guaranteed to ''not'' run on the same frame, on purpose. They are deliberately stored away and forced a delay of 6 sim-seconds. This is to avoid misuse of tasks, and infinite looping.&lt;br /&gt;
&lt;br /&gt;
This behavior might even be desirable in certain scripts, for example if you are developing some stateful signal system and you need some kind of “cleanup” task that makes sure some signal being owned by some train is still the focus of said train. You can deliberately queue tasks for future simulation frames with &amp;lt;code&amp;gt;queue_task_at&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;deadline&amp;lt;/code&amp;gt; is expressed as microseconds since the start of the current save world. You can obtain the current simulation frame &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; value with &amp;lt;code&amp;gt;Extrapolator::clock_us()&amp;lt;/code&amp;gt;, like in this example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;    // schedule task to run 10 sim-s from now&lt;br /&gt;
    sc.queue_task_at(task, ctx.extrapolator.clock_us() + 10000000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;event-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Event tasks ==&lt;br /&gt;
&lt;br /&gt;
Event tasks are a lightweight version of tasks which run when triggered by certain events. Unlike control tasks, event tasks do not have unlimited access to the sim. Instead the run under an &amp;lt;code&amp;gt;EventCtx&amp;lt;/code&amp;gt; like pub struct events, and run multithreaded, at the same time as the C++ code. Unlike the regular &amp;lt;code&amp;gt;event_*&amp;lt;/code&amp;gt; methods, event tasks are queued for execution by script code, not by UI player commands. The design idea of these tasks is to offer a more focused and efficient execution model than &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt;: they are executed immediately once the relevant event happens, in multithreaded context, rather than require passive polling which might even miss certain events and force execution of single thread code.&lt;br /&gt;
&lt;br /&gt;
Any function with a &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; parameter can queue an even task like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Task {...}&lt;br /&gt;
fn f(..., train: &amp;amp;amp;Train, sc: &amp;amp;amp;mut SimController) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    sc.queue_task_event_train(task, train, TaskEventTrain::StopDepart);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
On the next stop departure of the train the &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt; method will be called:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn Task::task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: TaskEventTrain,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == TaskEventTrain::StopDepart {&lt;br /&gt;
        log(&amp;amp;quot;@ departs&amp;amp;quot;, train);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Like control tasks, event tasks encapsulate a single call. If a series of calls are desired, the task can requeue itself by calling &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt;. Event tasks are limited to a maximum of 1 for every possible train-struct-event combination, to avoid leaks. Trying to queue again the same train-struct-event combination will overwrite any existing task. Only the train and motion are provided as parameters. The code can then drill into motion to extract any required information, like shift or line.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-controlctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ControlCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ControlCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    sim: &amp;amp;amp;Sim,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim controller scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects, and associated script stuct objects.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::track_pos_project(self: &amp;amp;amp;DB, pos: &amp;amp;amp;Pos, distance: f64): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return a track position separated by ‘distance’ meters from ‘pos’, in the direction of ‘pos’. If distance is negative it will be in the opposite direction. Can only follow the main track. Merges and dead ends will return a Pos a shorter distance away. Signals are ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view_self(self: &amp;amp;amp;DB): &amp;amp;amp;Script&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-eventctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type EventCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct EventCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim event handler scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line::Stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line::Stop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    cars_config: i32,&lt;br /&gt;
    dynamics: Train::Dynamics,&lt;br /&gt;
    hitched_by: Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    station_stop: std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;,&lt;br /&gt;
    run_stop: std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
    run_dispatch: std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;,&lt;br /&gt;
    hitch: std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motioncachedhitcher&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::CachedHitcher ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::CachedHitcher {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionhitch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Hitch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Hitch {&lt;br /&gt;
    driver_train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    flip: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Train is being hitched by a driver train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
    flip: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionrundispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::RunDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::RunDispatch {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a line run.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Motion::RunDispatch::current_stop(self: &amp;amp;amp;Motion::RunDispatch, line: &amp;amp;amp;Line): *Line::Stop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionstationstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::StationStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::StationStop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Schedule::view(self: &amp;amp;amp;Schedule, shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;): *Shift&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns a pointer to the shift, if it’s contained in this schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-script&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Script ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Script {&lt;br /&gt;
    id: ID&amp;amp;lt;Script&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Shift {&lt;br /&gt;
    id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::kind(self: &amp;amp;amp;Signal): mut SignalKind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the signal kind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-traindynamics&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train::Dynamics ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train::Dynamics {&lt;br /&gt;
    max_speed: f32,&lt;br /&gt;
    max_acceleration: f32,&lt;br /&gt;
    max_regular_braking: f32,&lt;br /&gt;
    max_emergency_braking: f32,&lt;br /&gt;
    max_tractive_effort: f32,&lt;br /&gt;
    total_power: f32,&lt;br /&gt;
    empty_mass: f32,&lt;br /&gt;
    length: f32,&lt;br /&gt;
    max_pax: i32,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vec&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;lt;Motion::CachedHitcher&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Hitch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;): *Motion::Hitch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStationEvent&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;&lt;br /&gt;
): *Motion::StationStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Script&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Shift&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Shift&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Shift&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciterator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;lt;Motion::CachedHitcher&amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator::next(&lt;br /&gt;
    self: &amp;amp;amp;mut Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator&lt;br /&gt;
): *Motion::CachedHitcher&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    idx: i64&lt;br /&gt;
): *Motion::CachedHitcher&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::clock_us(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current microseconds since the creation of this saved game. This is used as the timing root of the simulation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second since 1970-01-01:00:00:00.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_occupation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_reservation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying or reserving the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_occupying(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_reserving(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying or reserving the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
Probe a track position for train reservations and occupations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Seconds since 1970-01-01:00:00:00 for Monday 00:00:00 of the current week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestopevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type LineStopEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum LineStopEvent {&lt;br /&gt;
    Arrive,&lt;br /&gt;
    Depart,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
Advance the iterator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftallow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftAllow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftAllow {&lt;br /&gt;
    Allow,&lt;br /&gt;
    Deny,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftEvent {&lt;br /&gt;
    Assign,&lt;br /&gt;
    Unassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftsetup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftSetup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ShiftSetup {&lt;br /&gt;
    skip: bool,&lt;br /&gt;
    match_pos: bool,&lt;br /&gt;
    check_occupation: bool,&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores the context of a train shift lookup.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function wants to change the train path, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signallookaheadresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalLookaheadResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalLookaheadResult {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores extra information associated with the result of the signal lookahead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-sim&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Sim ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Sim {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of the simulation state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Sim::view&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Sim, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A proxy mutable API to the simulation engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    ev: TaskEventTrain&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_hitch(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    driver: &amp;amp;amp;Train,&lt;br /&gt;
    hitcher: &amp;amp;amp;Train,&lt;br /&gt;
    order: i64,&lt;br /&gt;
    flip: bool&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hitch a train to a driver train. The hitched train is emptied of pax and removed from the sim, while its cars are appended to the driver. The order parameter (from -1000 to 1000) determines the hitched train cars position: the driver train is always order 0, so negative values will put the hitch in front of the driver, and positive values behind it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(self: &amp;amp;amp;mut SimController, train: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_run_line(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    arrival_offset_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_configuration(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    config: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_presence_flip(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    flip: bool&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_stop_delay(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    delay_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Add extra delay time to a stopped train that has a timed_stop component.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_unhitch(self: &amp;amp;amp;mut SimController, hitcher: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Remove the hitched state from a train. It will become an unspawned, unassigned train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-taskeventtrain&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TaskEventTrain ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum TaskEventTrain {&lt;br /&gt;
    StopArrive,&lt;br /&gt;
    StopDepart,&lt;br /&gt;
    ShiftAssign,&lt;br /&gt;
    ShiftUnassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=555</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=555"/>
		<updated>2026-01-03T20:11:54Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used in game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration, integer division or arbitrary setting of pointers and references, and most data exposed to scripts is read-only, strictly enforced by the language. Any expression result which could result in an out of bounds or invalid memory access must be checked for validity, and the API design together with the type system enforces it.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
pub struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;SpeedTrap,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- VisMod? 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' ColonNAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Script&amp;lt;/code&amp;gt; (with restrictions)&lt;br /&gt;
&lt;br /&gt;
Structs extending game types for player extensions must be declared as &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt;. When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
To read struct objects from script code they must be looked up using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API. Therefore only functions provided with &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt; object (or a context object with contains &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt;) can look up these objects. But you can pass around &amp;lt;code&amp;gt;DB&amp;amp;amp;&amp;lt;/code&amp;gt; as a parameter without any lifetime restrictions, since it’s a purely read only API. This API also works for non-pub structs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= ctx.db.view&amp;amp;lt;Example&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    log(&amp;amp;quot;v = @&amp;amp;quot;, config.v);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;pub-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== pub structs ====&lt;br /&gt;
&lt;br /&gt;
As explained earlier, &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs are the user interface of your scripts. They are exposed in the UI as input forms, and their &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;s can give some control over this rendering. Conceptually they are owned by the player of the game as part of the game object database, by attaching them to a game model object in the database, not the script. Scripts do not have any capability to create, edit or delete objects of &amp;lt;code&amp;gt;pub struct&amp;lt;/code&amp;gt;s. It is always the player who decides when to create a new object of these structs by interacting in the UI. Scripts can then read, and only read, the content of these objects, by using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API presented earlier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs have a very powerful capability: they have limited support for forward schema evolution. This means that the script developer can add to, and reorder, fields in &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, and the game runtime will be able keep the contents of the other fields intact. This is very important to respect the input data by the player. If you rename &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs or their fields, or change their types, the player input data will be lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;non-pub-or-private-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Non-pub (or private) structs ====&lt;br /&gt;
&lt;br /&gt;
Non-&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, also called private structs, are conceptually owned by the script as a part of the simulation, not the player. Their contents are assumed to be a black box by the rest of the game. Scripts are allowed to create and modify objects of these structs during their execution, which are automatically deleted at the end of the simulation frame. It is also possible to attach these structs to existing game model objects to extend their lifetime beyond the current frame. In this case their lifetime becomes the same as the game object, and they can be retrieved in later frames for reading, deleted or overwritten as desired.&lt;br /&gt;
&lt;br /&gt;
Private structs ''do not support schema evolution''. Changing field types, field names, reordering of fields, even just adding new fields at the end, will always result in losing all existing attached objects of the given struct. Some operations like resetting the simulation will also erase attached objects, because they are considered simulation state, not player created objects.&lt;br /&gt;
&lt;br /&gt;
Private structs support dynamic memory allocation. All private struct definitions automatically create a &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; method for the struct:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct PrivData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let ro &amp;amp;amp;= ctx.db.view&amp;amp;lt;PrivData&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    let rw &amp;amp;amp;mut= ro.clone();&lt;br /&gt;
    rw.v = 100;&lt;br /&gt;
    let empty &amp;amp;amp;mut= PrivData::new();&lt;br /&gt;
    empty.v = 200;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The objects allocated by &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; are always deleted at the end of the current simulation frame. Their lifetime can be extended beyond the current frame by attaching them to a game object, like &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, so their lifetime becomes the same as the attached object. The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API has methods for attaching and erasing these object.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;host-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Host structs ====&lt;br /&gt;
&lt;br /&gt;
Many of the exposed game APIs are also based around structs. These structs do not follow any of the previous rules. Some have special capabilities, for example simple structs like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt; are ''value objects'': they can be copied and passed around like any &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; would. Some others are strictly locked down and serve as very little beyond a way to keep a pointer safe. In general, when working with game API structs, assume they are what would be called ''move only'' in C++. And NimbyScript has no move operator or semantics, so in essence assume they are immutable, immobile references, except when documented otherwise (like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As an aside, all script declared &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; or not) are also always ''move only'', and always “owned” by some external entity. This is why the APIs for their manipulation are always based on pointers and references, even for private structs. It is not possible to create plain, stack allocated values of script structs, or to use them as fields in structs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version:&lt;br /&gt;
&lt;br /&gt;
* Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
* Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums)&lt;br /&gt;
* For pub structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* For private structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In pub structs these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types. &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; will also display a small list editor. Keep in mind the correct type is &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;Vec&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- 'let' BindBody 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- 'let' BindBody ';'&lt;br /&gt;
BindBody    &amp;amp;lt;- NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' 'let' BindBody BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- ColonNAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere pointer types cannot be dereferenced, therefore cannot be used in dot expressions. The exception is the built-in function &amp;lt;code&amp;gt;is_valid(ptr): bool&amp;lt;/code&amp;gt;, which is usable with any pointer type.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;extensions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Extensions =&lt;br /&gt;
&lt;br /&gt;
Extending game database struct data with &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt; can also be used to extend the game code. The mechanism to do so is to first declare a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;ing a game database object (with or without fields). Then create a specifically named and parametrized function which will be called by the game under certain situations, for certain kinds of objects.&lt;br /&gt;
&lt;br /&gt;
All extension functions take a &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter which is a reference to the struct which it is method of, called &amp;lt;code&amp;gt;Example&amp;lt;/code&amp;gt; in the following sections. Replace it with your struct name. The rest of the parameters are fixed and must be reproduced exactly as-is.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
Event functions are called as part of the core simulation engine. They are meant to be focused in features and quick to execute. These functions might be called thousands of times per simulation frame, including multiple redundant times. Their capability to change the simulation behavior is usually very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_check&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_check ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails, or if another script call returns &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_lookahead&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_lookahead ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_lookahead(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    train_distance: f64,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalLookaheadResult&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; function at regular intervals for each signal 15km ahead of the train path. It is called for all signals, until one of these conditions hold: - One of the signals path checks as &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; - Another train is found - The train stop is found - 15km have been checked&lt;br /&gt;
&lt;br /&gt;
For both &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; signals, your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; will be called, and you can check the path find result in &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;, and the distance from the train in &amp;lt;code&amp;gt;train_distance&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; allows to set a maximum speed for the train, which goes into effect immediately. This works from any distance and past any amount of signals between the train and the caller signal. If multiple signals in the lookahead path return a &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt;, the slowest speed is picked. If no &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt; is set, or it is 0, the result is ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; default value is 0, which is considered invalid and will be ignored. To stop the train at the signal implement &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_change_path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_change_path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_change_path(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The current path check result of this signal for the passed train is passed as &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;. This already includes any results from &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_pass_by&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_pass_by ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_pass_by(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; function on the exact simulation frame a train passes by the exact point of the signal on the track.&lt;br /&gt;
&lt;br /&gt;
This function has no return result. Instead, since it has a predictably low call rate compared to the other events, it is the only event function with access to the powerful &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_marker_reserved&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_marker_reserved ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given marker signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; any time the reservation check algorithm is tracing a path which goes over the marker signal, on any direction, giving it the chance to report an arbitrary train as the reserver of that point on the track.&lt;br /&gt;
&lt;br /&gt;
This signal has a potential huge call rate, and for this reason it is given very little access to the APIs. The intention is that all the state required by this signal is calculated somewhere else and attached to the signal as a private struct object, or to some object reachable from it. Don’t worry about filtering for the “same train” cases, this is automatically done.&lt;br /&gt;
&lt;br /&gt;
If no reservation is desired, use the &amp;lt;code&amp;gt;empty&amp;lt;/code&amp;gt; global method available in all &amp;lt;code&amp;gt;ID&amp;amp;lt;Class&amp;amp;gt;&amp;lt;/code&amp;gt; types: &amp;lt;code&amp;gt;return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {}&lt;br /&gt;
struct Owner {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; {&lt;br /&gt;
    // some other, more full featured script function has attached Owner to this signal,&lt;br /&gt;
    // or not, so we need to check first&lt;br /&gt;
    if let owner &amp;amp;amp;= db.view&amp;amp;lt;Owner&amp;amp;gt;(signal) {&lt;br /&gt;
        if is_valid(db.view(owner.train_id)) {&lt;br /&gt;
            return owner.train_id;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_texture_state&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_texture_state ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_texture_state(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): i64 { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment, when the game UI needs to query what is the current signal texture state index, it will call your &amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt;, with some potential caching to keep the call rate lower. In any case the call rate of this function is potentially very large when the user zooms out the map, so make sure to keep its code as efficient as possible. For this same reason it is given very little access to the APIs.&lt;br /&gt;
&lt;br /&gt;
The return value indicates which signal texture state is to be used. If it’s -1 or lower, the default algorithm will be used to select the texture index. If it’s 0 or larger, it will select the texture in the same order as the &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; lines in the &amp;lt;code&amp;gt;SignalTextures&amp;lt;/code&amp;gt;. Larger values than the number of states will be clamped to the last state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_setup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_setup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_setup(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ss: &amp;amp;amp;mut ShiftSetup&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when an unassigned train decides to lookup a new shift to run, it will first call &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The parameter &amp;lt;code&amp;gt;ss&amp;lt;/code&amp;gt; is both an input and output parameter. It is initialized with the current, relevant data for the given train state, and &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; can then change it, to influence which shifts will be considered by the shift selection algorithm. It can change the train position used for matching, the time used for matching, and disable the check for reservations. For matched shifts which do not correspond to the current train position, the Extrapolator system will automatically pathfind a temporary milestone for the train, like other path-changing features.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_allow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_allow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_allow(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    run: &amp;amp;amp;Run,&lt;br /&gt;
    stop_idx: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    pose: &amp;amp;amp;Pose&lt;br /&gt;
): ShiftAllow { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when the shift selection algorithm fins a valid shift for the given train, it will call &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; with all the relevant data. The return of the function can then allow or deny the shift. If the shift is denied, the algorithm will resume immediately, trying other shifts&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are independent from each other, and can be used in any combination.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;linestop-event_line_stop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Line::Stop event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestStop extend Line::Stop {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestStop::event_line_stop(&lt;br /&gt;
    self: &amp;amp;amp;TestStop,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == LineStopEvent::Arrive {&lt;br /&gt;
        log(&amp;amp;quot;@ arrives @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ departs @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given line stop in the line editor. From that moment, when any train arrives or departs said line stop, &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LineStopEvent::Depart&amp;lt;/code&amp;gt; to distinguish between arrival and departure. Waypoints are only called for &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt;. Shift-less trains are also called.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;shift-event_shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Shift event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestShift extend Shift {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestShift::event_shift(&lt;br /&gt;
    self: &amp;amp;amp;TestShift,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == ShiftEvent::Assign {&lt;br /&gt;
        log(&amp;amp;quot;@ assigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ unassigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; requires the player to enable their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given schedule shift in the line editor. From that moment, when any train is assigned to the shift, or becomes unassigned from the shift, &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;ShiftEvent::Assign&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ShiftEvent::Unassign&amp;lt;/code&amp;gt; to distinguish between assignation and unassignation. The &amp;lt;code&amp;gt;Assign&amp;lt;/code&amp;gt; event is called just after &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been set up, so it already has all the shift and run information. The &amp;lt;code&amp;gt;Unassign&amp;lt;/code&amp;gt; event is called just before &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been cleared of all shift and run information so the script has access to as much information as possible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;controllers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Controllers ==&lt;br /&gt;
&lt;br /&gt;
Controller functions are called at a low frame rate compared to the overall simulation, with an (unchangeable) rate of once in 6 sim-seconds. They do not need any specific event or trigger to run, other than their enforced timer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-control_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train control_train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct HateDepots extend Train {}&lt;br /&gt;
pub fn HateDepots::control_train(&lt;br /&gt;
    self: &amp;amp;amp;HateDepots,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    // train is already removed from the tracks, don't interfere with potential attempts at shift assignation&lt;br /&gt;
    if !is_valid(motion.presence.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is running a schedule, don't interfere&lt;br /&gt;
    if is_valid(motion.schedule_dispatch.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is present, but it is not running a schedule, so despawn it&lt;br /&gt;
    sc.queue_train_intervention(train);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The train motion engine will call train controllers in the multithreaded phase, as part of the regular train motion extrapolator, after all the C++ code is done for a frame for a particular train, but before any queued commands are executed. Command execution will only happen after all train controllers for a given frame are done. In other words, train controllers queue up work to be executed by the sim. They never directly change the sim in any way, allowing train controller execution to be fully parallel.&lt;br /&gt;
&lt;br /&gt;
After all controllers are run, and all their non-task commands are executed, and then tasks are executed. Read more about tasks later on. Any tasks with a deadline which expired in this frame a run at this time too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontroller-command-queue&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== SimController command queue ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; object implements an API to control the simulation, including modification of some parameters and behaviors. It is also responsible for attaching and erasing private struct data from game objects, on behalf of scripts. The execution of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; is based on a command queue. Every call queues a command and returns immediately to the script code, without making any changes to the game state. Therefore the game state never changes while the script code is running.&lt;br /&gt;
&lt;br /&gt;
Commands queued from events and &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt; are executed asynchronously, there is no guaranteed order of execution! You must prepare your code and data for this design. For stand alone tasks scripts commands are executed in order and in isolation. You can queue up tasks from event and control scripts when you need to guarantee data consistency beyond “pick a random winner”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_intervention&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_intervention ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks, releases its schedule shift (if any), and deletes and refunds its pax (if any). No other cost other than pax refunds is issued. This function can be used as a general “despawn the train” feature, not just for exceptional circumstances.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_warp&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_warp ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks and repositions it at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, re-pathing it to its currently scheduled destination (if any), and setting its speed to 0. This is basically a train wormhole. The train keeps its shift and pax, if any.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_drive_to&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_drive_to ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Re-paths the train path to end at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, without any changes to its shift or pax (if any). It is possible for any future &amp;lt;code&amp;gt;queue_train_drive_to&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; to reset this path at any point, losing the destination. “Queue” here is used as part of the SimController API semantics, it does not mean the train keeps a queue of positions to reach. If the path is not interrupted and the train reaches &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; it will re-path itself towards its current scheduled stop, if it has any, or brake to a stop if unassigned. If &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; was also in the stop area set for its current scheduled stop it will also brake to stop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_attach&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_attach ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the attachment of the &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;existing.clone()&amp;lt;/code&amp;gt;) to the &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt;, which must be of one of the following types: &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attached objects can be accessed with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt; at some point in the future. If called from a controller function, the attached object will be accessible after all controller functions are done for a given frame. If called from a task, he attached object will be accessible immediately after the task returns, and before any other task is executed. In other words, tasks are transaction-like, in the sense they view an immutable snapshot of the game state, and any changes they queue are executed before any other task, and then visible from these other tasks.&lt;br /&gt;
&lt;br /&gt;
Attaching an object of a given private struct type when it already exists attached to a &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt; will overwrite it. This is how private data is updated from scripting: by using &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; to copy any existing data, modifying the copy, then calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; to replace the existing data. Therefore it is a good idea to keep your private structs small. Only one instance of a given private struct type can be attached to any particular model object, but you can attach as many different private struct types as you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_erase&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_erase ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the erasure of &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt;, which must obtained using with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt;. Trying to erase temporary objects (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;existing.clone()&amp;lt;/code&amp;gt;) is ignored. The execution of the queued erase commands is analog to the &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; case. In particular a sequences of attach and erase queued from controllers will produce undefined results (impossible to predict which attach and/or erase wins). For example multiple attach from a controller for the same model_obj and private struct type will implicitly pick a singular “winner” attach, but the script does not have any control over which one. Sequences of attach and erase queued from tasks are strictly ordered and isolated, so they produce consistent results, in the same order they were queued in the task script, without any concurrent changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task-and-simcontrollerqueue_task_at&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task and SimController::queue_task_at ===&lt;br /&gt;
&lt;br /&gt;
See [[#Control%20tasks|control tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task_event_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task_event_train ===&lt;br /&gt;
&lt;br /&gt;
See [[#Event%20tasks|event tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;control-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Control tasks ==&lt;br /&gt;
&lt;br /&gt;
Control tasks are a very special kind of command which allows scripts to dynamically queue “future work”, with privileged access to the sim. Scripts with access to &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; can call this function to queue up a task for future script execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; must be of a private struct type which implements &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example { ... }&lt;br /&gt;
pub fn Example::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
For example, a train controller script could decide it needs to delay some decision into a task for data consistency reasons (other controllers are running at the same time), and delegate into a task rather than directly calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ControlTrain extend Train { ... }&lt;br /&gt;
pub fn ControlTrain::control_train(&lt;br /&gt;
    self: &amp;amp;amp;ControlTrain,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    task.train_id = train.id;&lt;br /&gt;
    task.v = some_data_from_somewhere;&lt;br /&gt;
    task.prio = 42; // or something smarter, like from ControlTrain, other objects, etc.&lt;br /&gt;
    sc.queue_task(task);&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
struct Task {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
struct SomeData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
pub fn Task::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    let train &amp;amp;amp;= ctx.db.view(self.train_id) else { return; }&lt;br /&gt;
    if let existing &amp;amp;amp;= ctx.db.view&amp;amp;lt;SomeData&amp;amp;gt;(train) {&lt;br /&gt;
        if existing.prio &amp;amp;gt;= self.prio {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    let data = SomeData::new();&lt;br /&gt;
    data.v = self.v;&lt;br /&gt;
    data.prio = self.prio;&lt;br /&gt;
    sc.queue_attach(train, data);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the previous example, maybe &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; will be called multiple times because multiple &amp;lt;code&amp;gt;ControlTrain::control_train()&amp;lt;/code&amp;gt; instances queued objects of &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;, but each execution will be single threaded, and all its queued &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; commands will be executed just after the call is done and before any other &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; call (for &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; or any other struct type), therefore the algorithm to pick a winner based on an explicit priority works.&lt;br /&gt;
&lt;br /&gt;
As mentioned, task execution is single threaded. The game does not feature a real concurrent database, instead all concurrent access is bespoke and very carefully designed to avoid deadlocks and inconsistencies (this is much faster than a general purpose concurrent database). Scripts also run in this parallel system, but their access to the game state is carefully restricted as explained earlier. But in the end, scripts also need to modify data, and do so in a consistent way. Tasks solve this issue, but do so in the most pessimistic possible way, by being single threaded. Therefore script developers should use them in moderation. Consider the “random winner” semantics of control script queuing first, which are completely free performance wise, before deciding you need a task. It is often the case a concurrent problem reduces to “pick 0 or 1 winners, any winner, but never 2 or more” and the default queue semantics already provide that guarantee for attaching a specific model/private pair.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; is provided with &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt;, therefore it can queue tasks itself. But unlike controller queuing tasks, which are guaranteed to run on the same frame, tasks queued from tasks are guaranteed to ''not'' run on the same frame, on purpose. They are deliberately stored away and forced a delay of 6 sim-seconds. This is to avoid misuse of tasks, and infinite looping.&lt;br /&gt;
&lt;br /&gt;
This behavior might even be desirable in certain scripts, for example if you are developing some stateful signal system and you need some kind of “cleanup” task that makes sure some signal being owned by some train is still the focus of said train. You can deliberately queue tasks for future simulation frames with &amp;lt;code&amp;gt;queue_task_at&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;deadline&amp;lt;/code&amp;gt; is expressed as microseconds since the start of the current save world. You can obtain the current simulation frame &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; value with &amp;lt;code&amp;gt;Extrapolator::clock_us()&amp;lt;/code&amp;gt;, like in this example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;    // schedule task to run 10 sim-s from now&lt;br /&gt;
    sc.queue_task_at(task, ctx.extrapolator.clock_us() + 10000000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;event-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Event tasks ==&lt;br /&gt;
&lt;br /&gt;
Event tasks are a lightweight version of tasks which run when triggered by certain events. Unlike control tasks, event tasks do not have unlimited access to the sim. Instead the run under an &amp;lt;code&amp;gt;EventCtx&amp;lt;/code&amp;gt; like pub struct events, and run multithreaded, at the same time as the C++ code. Unlike the regular &amp;lt;code&amp;gt;event_*&amp;lt;/code&amp;gt; methods, event tasks are queued for execution by script code, not by UI player commands. The design idea of these tasks is to offer a more focused and efficient execution model than &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt;: they are executed immediately once the relevant event happens, in multithreaded context, rather than require passive polling which might even miss certain events and force execution of single thread code.&lt;br /&gt;
&lt;br /&gt;
Any function with a &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; parameter can queue an even task like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Task {...}&lt;br /&gt;
fn f(..., train: &amp;amp;amp;Train, sc: &amp;amp;amp;mut SimController) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    sc.queue_task_event_train(task, train, TaskEventTrain::StopDepart);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
On the next stop departure of the train the &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt; method will be called:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn Task::task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: TaskEventTrain,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == TaskEventTrain::StopDepart {&lt;br /&gt;
        log(&amp;amp;quot;@ departs&amp;amp;quot;, train);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Like control tasks, event tasks encapsulate a single call. If a series of calls are desired, the task can requeue itself by calling &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt;. Event tasks are limited to a maximum of 1 for every possible train-struct-event combination, to avoid leaks. Trying to queue again the same train-struct-event combination will overwrite any existing task. Only the train and motion are provided as parameters. The code can then drill into motion to extract any required information, like shift or line.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-controlctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ControlCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ControlCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    sim: &amp;amp;amp;Sim,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim controller scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects, and associated script stuct objects.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::track_pos_project(self: &amp;amp;amp;DB, pos: &amp;amp;amp;Pos, distance: f64): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return a track position separated by ‘distance’ meters from ‘pos’, in the direction of ‘pos’. If distance is negative it will be in the opposite direction. Can only follow the main track. Merges and dead ends will return a Pos a shorter distance away. Signals are ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB): &amp;amp;amp;Script&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-eventctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type EventCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct EventCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim event handler scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line::Stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line::Stop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    cars_config: i32,&lt;br /&gt;
    dynamics: Train::Dynamics,&lt;br /&gt;
    hitched_by: Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    station_stop: std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;,&lt;br /&gt;
    run_stop: std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
    run_dispatch: std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;,&lt;br /&gt;
    hitch: std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motioncachedhitcher&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::CachedHitcher ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::CachedHitcher {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionhitch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Hitch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Hitch {&lt;br /&gt;
    driver_train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Train is being hitched by a driver train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionrundispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::RunDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::RunDispatch {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a line run.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Motion::RunDispatch::current_stop(self: &amp;amp;amp;Motion::RunDispatch, line: &amp;amp;amp;Line): *Line::Stop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionstationstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::StationStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::StationStop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Schedule::view(self: &amp;amp;amp;Schedule, shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;): *Shift&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns a pointer to the shift, if it’s contained in this schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-script&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Script ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Script {&lt;br /&gt;
    id: ID&amp;amp;lt;Script&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Shift {&lt;br /&gt;
    id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::kind(self: &amp;amp;amp;Signal): mut SignalKind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the signal kind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-traindynamics&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train::Dynamics ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train::Dynamics {&lt;br /&gt;
    max_speed: f32,&lt;br /&gt;
    max_acceleration: f32,&lt;br /&gt;
    max_regular_braking: f32,&lt;br /&gt;
    max_emergency_braking: f32,&lt;br /&gt;
    max_tractive_effort: f32,&lt;br /&gt;
    total_power: f32,&lt;br /&gt;
    empty_mass: f32,&lt;br /&gt;
    length: f32,&lt;br /&gt;
    max_pax: i32,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vec&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;lt;Motion::CachedHitcher&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Hitch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;): *Motion::Hitch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStationEvent&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;&lt;br /&gt;
): *Motion::StationStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Script&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Shift&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Shift&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Shift&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciterator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;lt;Motion::CachedHitcher&amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator::next(&lt;br /&gt;
    self: &amp;amp;amp;mut Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator&lt;br /&gt;
): *Motion::CachedHitcher&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;,&lt;br /&gt;
    idx: i64&lt;br /&gt;
): *Motion::CachedHitcher&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;Motion::CachedHitcher&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::clock_us(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current microseconds since the creation of this saved game. This is used as the timing root of the simulation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second since 1970-01-01:00:00:00.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_occupation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_reservation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying or reserving the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_occupying(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_reserving(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying or reserving the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
Probe a track position for train reservations and occupations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Seconds since 1970-01-01:00:00:00 for Monday 00:00:00 of the current week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestopevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type LineStopEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum LineStopEvent {&lt;br /&gt;
    Arrive,&lt;br /&gt;
    Depart,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
Advance the iterator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftallow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftAllow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftAllow {&lt;br /&gt;
    Allow,&lt;br /&gt;
    Deny,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftEvent {&lt;br /&gt;
    Assign,&lt;br /&gt;
    Unassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftsetup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftSetup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ShiftSetup {&lt;br /&gt;
    skip: bool,&lt;br /&gt;
    match_pos: bool,&lt;br /&gt;
    check_occupation: bool,&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores the context of a train shift lookup.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function wants to change the train path, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signallookaheadresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalLookaheadResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalLookaheadResult {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores extra information associated with the result of the signal lookahead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-sim&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Sim ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Sim {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of the simulation state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Sim::view&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Sim, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A proxy mutable API to the simulation engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    ev: TaskEventTrain&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_hitch(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    driver: &amp;amp;amp;Train,&lt;br /&gt;
    hitcher: &amp;amp;amp;Train,&lt;br /&gt;
    order: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Hitch a train to a driver train. The hitched train is emptied of pax and removed from the sim, while its cars are appended to the driver. The order parameter (from -1000 to 1000) determines the hitched train cars position: the driver train is always order 0, so negative values will put the hitch in front of the driver, and positive values behind it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(self: &amp;amp;amp;mut SimController, train: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_run_line(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    arrival_offset_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_configuration(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    config: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_unhitch(self: &amp;amp;amp;mut SimController, hitcher: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
Remove the hitched state from a train. It will become an unspawned, unassigned train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-taskeventtrain&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TaskEventTrain ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum TaskEventTrain {&lt;br /&gt;
    StopArrive,&lt;br /&gt;
    StopDepart,&lt;br /&gt;
    ShiftAssign,&lt;br /&gt;
    ShiftUnassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=554</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=554"/>
		<updated>2025-12-30T10:58:55Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used in game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration, integer division or arbitrary setting of pointers and references, and most data exposed to scripts is read-only, strictly enforced by the language. Any expression result which could result in an out of bounds or invalid memory access must be checked for validity, and the API design together with the type system enforces it.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
pub struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;SpeedTrap,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- VisMod? 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' ColonNAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Script&amp;lt;/code&amp;gt; (with restrictions)&lt;br /&gt;
&lt;br /&gt;
Structs extending game types for player extensions must be declared as &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt;. When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
To read struct objects from script code they must be looked up using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API. Therefore only functions provided with &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt; object (or a context object with contains &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt;) can look up these objects. But you can pass around &amp;lt;code&amp;gt;DB&amp;amp;amp;&amp;lt;/code&amp;gt; as a parameter without any lifetime restrictions, since it’s a purely read only API. This API also works for non-pub structs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= ctx.db.view&amp;amp;lt;Example&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    log(&amp;amp;quot;v = @&amp;amp;quot;, config.v);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;pub-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== pub structs ====&lt;br /&gt;
&lt;br /&gt;
As explained earlier, &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs are the user interface of your scripts. They are exposed in the UI as input forms, and their &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;s can give some control over this rendering. Conceptually they are owned by the player of the game as part of the game object database, by attaching them to a game model object in the database, not the script. Scripts do not have any capability to create, edit or delete objects of &amp;lt;code&amp;gt;pub struct&amp;lt;/code&amp;gt;s. It is always the player who decides when to create a new object of these structs by interacting in the UI. Scripts can then read, and only read, the content of these objects, by using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API presented earlier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs have a very powerful capability: they have limited support for forward schema evolution. This means that the script developer can add to, and reorder, fields in &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, and the game runtime will be able keep the contents of the other fields intact. This is very important to respect the input data by the player. If you rename &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs or their fields, or change their types, the player input data will be lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;non-pub-or-private-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Non-pub (or private) structs ====&lt;br /&gt;
&lt;br /&gt;
Non-&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, also called private structs, are conceptually owned by the script as a part of the simulation, not the player. Their contents are assumed to be a black box by the rest of the game. Scripts are allowed to create and modify objects of these structs during their execution, which are automatically deleted at the end of the simulation frame. It is also possible to attach these structs to existing game model objects to extend their lifetime beyond the current frame. In this case their lifetime becomes the same as the game object, and they can be retrieved in later frames for reading, deleted or overwritten as desired.&lt;br /&gt;
&lt;br /&gt;
Private structs ''do not support schema evolution''. Changing field types, field names, reordering of fields, even just adding new fields at the end, will always result in losing all existing attached objects of the given struct. Some operations like resetting the simulation will also erase attached objects, because they are considered simulation state, not player created objects.&lt;br /&gt;
&lt;br /&gt;
Private structs support dynamic memory allocation. All private struct definitions automatically create a &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; method for the struct:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct PrivData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let ro &amp;amp;amp;= ctx.db.view&amp;amp;lt;PrivData&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    let rw &amp;amp;amp;mut= PrivData::clone(ro);&lt;br /&gt;
    rw.v = 100;&lt;br /&gt;
    let empty &amp;amp;amp;mut= PrivData::new();&lt;br /&gt;
    empty.v = 200;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The objects allocated by &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; are always deleted at the end of the current simulation frame. Their lifetime can be extended beyond the current frame by attaching them to a game object, like &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, so their lifetime becomes the same as the attached object. The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API has methods for attaching and erasing these object.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;host-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Host structs ====&lt;br /&gt;
&lt;br /&gt;
Many of the exposed game APIs are also based around structs. These structs do not follow any of the previous rules. Some have special capabilities, for example simple structs like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt; are ''value objects'': they can be copied and passed around like any &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; would. Some others are strictly locked down and serve as very little beyond a way to keep a pointer safe. In general, when working with game API structs, assume they are what would be called ''move only'' in C++. And NimbyScript has no move operator or semantics, so in essence assume they are immutable, immobile references, except when documented otherwise (like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As an aside, all script declared &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; or not) are also always ''move only'', and always “owned” by some external entity. This is why the APIs for their manipulation are always based on pointers and references, even for private structs. It is not possible to create plain, stack allocated values of script structs, or to use them as fields in structs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version:&lt;br /&gt;
&lt;br /&gt;
* Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
* Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums)&lt;br /&gt;
* For pub structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* For private structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In pub structs these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types. &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; will also display a small list editor. Keep in mind the correct type is &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;Vec&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- 'let' BindBody 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- 'let' BindBody ';'&lt;br /&gt;
BindBody    &amp;amp;lt;- NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' 'let' BindBody BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- ColonNAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere pointer types cannot be dereferenced, therefore cannot be used in dot expressions. The exception is the built-in function &amp;lt;code&amp;gt;is_valid(ptr): bool&amp;lt;/code&amp;gt;, which is usable with any pointer type.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;extensions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Extensions =&lt;br /&gt;
&lt;br /&gt;
Extending game database struct data with &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt; can also be used to extend the game code. The mechanism to do so is to first declare a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;ing a game database object (with or without fields). Then create a specifically named and parametrized function which will be called by the game under certain situations, for certain kinds of objects.&lt;br /&gt;
&lt;br /&gt;
All extension functions take a &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter which is a reference to the struct which it is method of, called &amp;lt;code&amp;gt;Example&amp;lt;/code&amp;gt; in the following sections. Replace it with your struct name. The rest of the parameters are fixed and must be reproduced exactly as-is.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
Event functions are called as part of the core simulation engine. They are meant to be focused in features and quick to execute. These functions might be called thousands of times per simulation frame, including multiple redundant times. Their capability to change the simulation behavior is usually very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_check&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_check ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails, or if another script call returns &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_lookahead&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_lookahead ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_lookahead(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    train_distance: f64,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalLookaheadResult&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; function at regular intervals for each signal 15km ahead of the train path. It is called for all signals, until one of these conditions hold: - One of the signals path checks as &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; - Another train is found - The train stop is found - 15km have been checked&lt;br /&gt;
&lt;br /&gt;
For both &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; signals, your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; will be called, and you can check the path find result in &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;, and the distance from the train in &amp;lt;code&amp;gt;train_distance&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; allows to set a maximum speed for the train, which goes into effect immediately. This works from any distance and past any amount of signals between the train and the caller signal. If multiple signals in the lookahead path return a &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt;, the slowest speed is picked. If no &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt; is set, or it is 0, the result is ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; default value is 0, which is considered invalid and will be ignored. To stop the train at the signal implement &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_change_path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_change_path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_change_path(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The current path check result of this signal for the passed train is passed as &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;. This already includes any results from &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_pass_by&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_pass_by ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_pass_by(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; function on the exact simulation frame a train passes by the exact point of the signal on the track.&lt;br /&gt;
&lt;br /&gt;
This function has no return result. Instead, since it has a predictably low call rate compared to the other events, it is the only event function with access to the powerful &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_marker_reserved&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_marker_reserved ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given marker signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; any time the reservation check algorithm is tracing a path which goes over the marker signal, on any direction, giving it the chance to report an arbitrary train as the reserver of that point on the track.&lt;br /&gt;
&lt;br /&gt;
This signal has a potential huge call rate, and for this reason it is given very little access to the APIs. The intention is that all the state required by this signal is calculated somewhere else and attached to the signal as a private struct object, or to some object reachable from it. Don’t worry about filtering for the “same train” cases, this is automatically done.&lt;br /&gt;
&lt;br /&gt;
If no reservation is desired, use the &amp;lt;code&amp;gt;empty&amp;lt;/code&amp;gt; global method available in all &amp;lt;code&amp;gt;ID&amp;amp;lt;Class&amp;amp;gt;&amp;lt;/code&amp;gt; types: &amp;lt;code&amp;gt;return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {}&lt;br /&gt;
struct Owner {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; {&lt;br /&gt;
    // some other, more full featured script function has attached Owner to this signal,&lt;br /&gt;
    // or not, so we need to check first&lt;br /&gt;
    if let owner &amp;amp;amp;= db.view&amp;amp;lt;Owner&amp;amp;gt;(signal) {&lt;br /&gt;
        if is_valid(db.view(owner.train_id)) {&lt;br /&gt;
            return owner.train_id;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_texture_state&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_texture_state ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_texture_state(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): i64 { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment, when the game UI needs to query what is the current signal texture state index, it will call your &amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt;, with some potential caching to keep the call rate lower. In any case the call rate of this function is potentially very large when the user zooms out the map, so make sure to keep its code as efficient as possible. For this same reason it is given very little access to the APIs.&lt;br /&gt;
&lt;br /&gt;
The return value indicates which signal texture state is to be used. If it’s -1 or lower, the default algorithm will be used to select the texture index. If it’s 0 or larger, it will select the texture in the same order as the &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; lines in the &amp;lt;code&amp;gt;SignalTextures&amp;lt;/code&amp;gt;. Larger values than the number of states will be clamped to the last state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_setup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_setup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_setup(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ss: &amp;amp;amp;mut ShiftSetup&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when an unassigned train decides to lookup a new shift to run, it will first call &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The parameter &amp;lt;code&amp;gt;ss&amp;lt;/code&amp;gt; is both an input and output parameter. It is initialized with the current, relevant data for the given train state, and &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; can then change it, to influence which shifts will be considered by the shift selection algorithm. It can change the train position used for matching, the time used for matching, and disable the check for reservations. For matched shifts which do not correspond to the current train position, the Extrapolator system will automatically pathfind a temporary milestone for the train, like other path-changing features.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_allow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_allow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_allow(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    run: &amp;amp;amp;Run,&lt;br /&gt;
    stop_idx: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    pose: &amp;amp;amp;Pose&lt;br /&gt;
): ShiftAllow { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when the shift selection algorithm fins a valid shift for the given train, it will call &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; with all the relevant data. The return of the function can then allow or deny the shift. If the shift is denied, the algorithm will resume immediately, trying other shifts&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are independent from each other, and can be used in any combination.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;linestop-event_line_stop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Line::Stop event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestStop extend Line::Stop {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestStop::event_line_stop(&lt;br /&gt;
    self: &amp;amp;amp;TestStop,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == LineStopEvent::Arrive {&lt;br /&gt;
        log(&amp;amp;quot;@ arrives @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ departs @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given line stop in the line editor. From that moment, when any train arrives or departs said line stop, &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LineStopEvent::Depart&amp;lt;/code&amp;gt; to distinguish between arrival and departure. Waypoints are only called for &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt;. Shift-less trains are also called.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;shift-event_shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Shift event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestShift extend Shift {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestShift::event_shift(&lt;br /&gt;
    self: &amp;amp;amp;TestShift,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == ShiftEvent::Assign {&lt;br /&gt;
        log(&amp;amp;quot;@ assigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ unassigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given schedule shift in the line editor. From that moment, when any train is assigned to the shift, or becomes unassigned from the shift, &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;ShiftEvent::Assign&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ShiftEvent::Unassign&amp;lt;/code&amp;gt; to distinguish between assignation and unassignation. The &amp;lt;code&amp;gt;Assign&amp;lt;/code&amp;gt; event is called just after &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been set up, so it already has all the shift and run information. The &amp;lt;code&amp;gt;Unassign&amp;lt;/code&amp;gt; event is called just before &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been cleared of all shift and run information so the script has access to as much information as possible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;controllers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Controllers ==&lt;br /&gt;
&lt;br /&gt;
Controller functions are called at a low frame rate compared to the overall simulation, with an (unchangeable) rate of once in 6 sim-seconds. They do not need any specific event or trigger to run, other than their enforced timer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-control_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train control_train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct HateDepots extend Train {}&lt;br /&gt;
pub fn HateDepots::control_train(&lt;br /&gt;
    self: &amp;amp;amp;HateDepots,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    // train is already removed from the tracks, don't interfere with potential attempts at shift assignation&lt;br /&gt;
    if !is_valid(motion.presence.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is running a schedule, don't interfere&lt;br /&gt;
    if is_valid(motion.schedule_dispatch.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is present, but it is not running a schedule, so despawn it&lt;br /&gt;
    sc.queue_train_intervention(train);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The train motion engine will call train controllers in the multithreaded phase, as part of the regular train motion extrapolator, after all the C++ code is done for a frame for a particular train, but before any queued commands are executed. Command execution will only happen after all train controllers for a given frame are done. In other words, train controllers queue up work to be executed by the sim. They never directly change the sim in any way, allowing train controller execution to be fully parallel.&lt;br /&gt;
&lt;br /&gt;
After all controllers are run, and all their non-task commands are executed, and then tasks are executed. Read more about tasks later on. Any tasks with a deadline which expired in this frame a run at this time too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontroller-command-queue&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== SimController command queue ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; object implements an API to control the simulation, including modification of some parameters and behaviors. It is also responsible for attaching and erasing private struct data from game objects, on behalf of scripts. The execution of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; is based on a command queue. Every call queues a command and returns immediately to the script code, without making any changes to the game state. Therefore the game state never changes while the script code is running.&lt;br /&gt;
&lt;br /&gt;
Commands queued from events and &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt; are executed asynchronously, there is no guaranteed order of execution! You must prepare your code and data for this design. For stand alone tasks scripts commands are executed in order and in isolation. You can queue up tasks from event and control scripts when you need to guarantee data consistency beyond “pick a random winner”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_intervention&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_intervention ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks, releases its schedule shift (if any), and deletes and refunds its pax (if any). No other cost other than pax refunds is issued. This function can be used as a general “despawn the train” feature, not just for exceptional circumstances.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_warp&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_warp ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks and repositions it at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, re-pathing it to its currently scheduled destination (if any), and setting its speed to 0. This is basically a train wormhole. The train keeps its shift and pax, if any.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_drive_to&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_drive_to ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Re-paths the train path to end at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, without any changes to its shift or pax (if any). It is possible for any future &amp;lt;code&amp;gt;queue_train_drive_to&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; to reset this path at any point, losing the destination. “Queue” here is used as part of the SimController API semantics, it does not mean the train keeps a queue of positions to reach. If the path is not interrupted and the train reaches &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; it will re-path itself towards its current scheduled stop, if it has any, or brake to a stop if unassigned. If &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; was also in the stop area set for its current scheduled stop it will also brake to stop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_attach&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_attach ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the attachment of the &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) to the &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt;, which must be of one of the following types: &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attached objects can be accessed with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt; at some point in the future. If called from a controller function, the attached object will be accessible after all controller functions are done for a given frame. If called from a task, he attached object will be accessible immediately after the task returns, and before any other task is executed. In other words, tasks are transaction-like, in the sense they view an immutable snapshot of the game state, and any changes they queue are executed before any other task, and then visible from these other tasks.&lt;br /&gt;
&lt;br /&gt;
Attaching an object of a given private struct type when it already exists attached to a &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt; will overwrite it. This is how private data is updated from scripting: by using &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; to copy any existing data, modifying the copy, then calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; to replace the existing data. Therefore it is a good idea to keep your private structs small. Only one instance of a given private struct type can be attached to any particular model object, but you can attach as many different private struct types as you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_erase&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_erase ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the erasure of &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt;, which must obtained using with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt;. Trying to erase temporary objects (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) is ignored. The execution of the queued erase commands is analog to the &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; case. In particular a sequences of attach and erase queued from controllers will produce undefined results (impossible to predict which attach and/or erase wins). For example multiple attach from a controller for the same model_obj and private struct type will implicitly pick a singular “winner” attach, but the script does not have any control over which one. Sequences of attach and erase queued from tasks are strictly ordered and isolated, so they produce consistent results, in the same order they were queued in the task script, without any concurrent changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task-and-simcontrollerqueue_task_at&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task and SimController::queue_task_at ===&lt;br /&gt;
&lt;br /&gt;
See [[#Control%20tasks|control tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task_event_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task_event_train ===&lt;br /&gt;
&lt;br /&gt;
See [[#Event%20tasks|event tasks]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;control-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Control tasks ==&lt;br /&gt;
&lt;br /&gt;
Control tasks are a very special kind of command which allows scripts to dynamically queue “future work”, with privileged access to the sim. Scripts with access to &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; can call this function to queue up a task for future script execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; must be of a private struct type which implements &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example { ... }&lt;br /&gt;
pub fn Example::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
For example, a train controller script could decide it needs to delay some decision into a task for data consistency reasons (other controllers are running at the same time), and delegate into a task rather than directly calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ControlTrain extend Train { ... }&lt;br /&gt;
pub fn ControlTrain::control_train(&lt;br /&gt;
    self: &amp;amp;amp;ControlTrain,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    task.train_id = train.id;&lt;br /&gt;
    task.v = some_data_from_somewhere;&lt;br /&gt;
    task.prio = 42; // or something smarter, like from ControlTrain, other objects, etc.&lt;br /&gt;
    sc.queue_task(task);&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
struct Task {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
struct SomeData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
pub fn Task::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    let train &amp;amp;amp;= ctx.db.view(self.train_id) else { return; }&lt;br /&gt;
    if let existing &amp;amp;amp;= ctx.db.view&amp;amp;lt;SomeData&amp;amp;gt;(train) {&lt;br /&gt;
        if existing.prio &amp;amp;gt;= self.prio {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    let data = SomeData::new();&lt;br /&gt;
    data.v = self.v;&lt;br /&gt;
    data.prio = self.prio;&lt;br /&gt;
    sc.queue_attach(train, data);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the previous example, maybe &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; will be called multiple times because multiple &amp;lt;code&amp;gt;ControlTrain::control_train()&amp;lt;/code&amp;gt; instances queued objects of &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;, but each execution will be single threaded, and all its queued &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; commands will be executed just after the call is done and before any other &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; call (for &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; or any other struct type), therefore the algorithm to pick a winner based on an explicit priority works.&lt;br /&gt;
&lt;br /&gt;
As mentioned, task execution is single threaded. The game does not feature a real concurrent database, instead all concurrent access is bespoke and very carefully designed to avoid deadlocks and inconsistencies (this is much faster than a general purpose concurrent database). Scripts also run in this parallel system, but their access to the game state is carefully restricted as explained earlier. But in the end, scripts also need to modify data, and do so in a consistent way. Tasks solve this issue, but do so in the most pessimistic possible way, by being single threaded. Therefore script developers should use them in moderation. Consider the “random winner” semantics of control script queuing first, which are completely free performance wise, before deciding you need a task. It is often the case a concurrent problem reduces to “pick 0 or 1 winners, any winner, but never 2 or more” and the default queue semantics already provide that guarantee for attaching a specific model/private pair.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; is provided with &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt;, therefore it can queue tasks itself. But unlike controller queuing tasks, which are guaranteed to run on the same frame, tasks queued from tasks are guaranteed to ''not'' run on the same frame, on purpose. They are deliberately stored away and forced a delay of 6 sim-seconds. This is to avoid misuse of tasks, and infinite looping.&lt;br /&gt;
&lt;br /&gt;
This behavior might even be desirable in certain scripts, for example if you are developing some stateful signal system and you need some kind of “cleanup” task that makes sure some signal being owned by some train is still the focus of said train. You can deliberately queue tasks for future simulation frames with &amp;lt;code&amp;gt;queue_task_at&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;deadline&amp;lt;/code&amp;gt; is expressed as microseconds since the start of the current save world. You can obtain the current simulation frame &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; value with &amp;lt;code&amp;gt;Extrapolator::clock_us()&amp;lt;/code&amp;gt;, like in this example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;    // schedule task to run 10 sim-s from now&lt;br /&gt;
    sc.queue_task_at(task, ctx.extrapolator.clock_us() + 10000000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;event-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Event tasks ==&lt;br /&gt;
&lt;br /&gt;
Event tasks are a lightweight version of tasks which run when triggered by certain events. Unlike control tasks, event tasks do not have unlimited access to the sim. Instead the run under an &amp;lt;code&amp;gt;EventCtx&amp;lt;/code&amp;gt; like pub struct events, and run multithreaded, at the same time as the C++ code. Unlike the regular &amp;lt;code&amp;gt;event_*&amp;lt;/code&amp;gt; methods, event tasks are queued for execution by script code, not by UI player commands. The design idea of these tasks is to offer a more focused and efficient execution model than &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt;: they are executed immediately once the relevant event happens, in multithreaded context, rather than require passive polling which might even miss certain events and force execution of single thread code.&lt;br /&gt;
&lt;br /&gt;
Any function with a &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; parameter can queue an even task like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Task {...}&lt;br /&gt;
fn f(..., train: &amp;amp;amp;Train, sc: &amp;amp;amp;mut SimController) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    sc.queue_task_event_train(task, train, TaskEventTrain::StopDepart);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
On the next stop departure of the train the &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt; method will be called:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn Task::task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: TaskEventTrain,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == TaskEventTrain::StopDepart {&lt;br /&gt;
        log(&amp;amp;quot;@ departs&amp;amp;quot;, train);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Like control tasks, event tasks encapsulate a single call. If a series of calls are desired, the task can requeue itself by calling &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt;. Event tasks are limited to a maximum of 1 for every possible train-struct-event combination, to avoid leaks. Trying to queue again the same train-struct-event combination will overwrite any existing task. Only the train and motion are provided as parameters. The code can then drill into motion to extract any required information, like shift or line.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-controlctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ControlCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ControlCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    sim: &amp;amp;amp;Sim,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim controller scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects, and associated script stuct objects.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::track_pos_project(self: &amp;amp;amp;DB, pos: &amp;amp;amp;Pos, distance: f64): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return a track position separated by ‘distance’ meters from ‘pos’, in the direction of ‘pos’. If distance is negative it will be in the opposite direction. Can only follow the main track. Merges and dead ends will return a Pos a shorter distance away. Signals are ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB): &amp;amp;amp;Script&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-eventctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type EventCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct EventCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim event handler scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line::Stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line::Stop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    station_stop: std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;,&lt;br /&gt;
    run_stop: std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
    run_dispatch: std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;,&lt;br /&gt;
    hitch: std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionhitch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Hitch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Hitch {&lt;br /&gt;
    driver_train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Train is being hitched by a driver train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionrundispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::RunDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::RunDispatch {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a line run.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Motion::RunDispatch::current_stop(self: &amp;amp;amp;Motion::RunDispatch, line: &amp;amp;amp;Line): *Line::Stop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionstationstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::StationStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::StationStop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Schedule::view(self: &amp;amp;amp;Schedule, shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;): *Shift&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns a pointer to the shift, if it’s contained in this schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-script&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Script ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Script {&lt;br /&gt;
    id: ID&amp;amp;lt;Script&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Shift {&lt;br /&gt;
    id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::kind(self: &amp;amp;amp;Signal): mut SignalKind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the signal kind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Hitch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;): *Motion::Hitch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStationEvent&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;&lt;br /&gt;
): *Motion::StationStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Script&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Shift&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Shift&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Shift&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::clock_us(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current microseconds since the creation of this saved game. This is used as the timing root of the simulation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second since 1970-01-01:00:00:00.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_occupation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_reservation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying or reserving the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_occupying(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_reserving(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying or reserving the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
Probe a track position for train reservations and occupations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Seconds since 1970-01-01:00:00:00 for Monday 00:00:00 of the current week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestopevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type LineStopEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum LineStopEvent {&lt;br /&gt;
    Arrive,&lt;br /&gt;
    Depart,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
Advance the iterator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftallow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftAllow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftAllow {&lt;br /&gt;
    Allow,&lt;br /&gt;
    Deny,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftEvent {&lt;br /&gt;
    Assign,&lt;br /&gt;
    Unassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftsetup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftSetup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ShiftSetup {&lt;br /&gt;
    skip: bool,&lt;br /&gt;
    match_pos: bool,&lt;br /&gt;
    check_occupation: bool,&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores the context of a train shift lookup.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function wants to change the train path, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signallookaheadresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalLookaheadResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalLookaheadResult {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores extra information associated with the result of the signal lookahead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-sim&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Sim ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Sim {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of the simulation state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Sim::view&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Sim, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A proxy mutable API to the simulation engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    ev: TaskEventTrain&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_hitch(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    driver: &amp;amp;amp;Train,&lt;br /&gt;
    hitcher: &amp;amp;amp;Train&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(self: &amp;amp;amp;mut SimController, train: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_run_line(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    arrival_offset_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_configuration(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    config: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_unhitch(self: &amp;amp;amp;mut SimController, hitcher: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-taskeventtrain&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TaskEventTrain ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum TaskEventTrain {&lt;br /&gt;
    StopArrive,&lt;br /&gt;
    StopDepart,&lt;br /&gt;
    ShiftAssign,&lt;br /&gt;
    ShiftUnassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=553</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=553"/>
		<updated>2025-12-29T19:33:46Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used in game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration, integer division or arbitrary setting of pointers and references, and most data exposed to scripts is read-only, strictly enforced by the language. Any expression result which could result in an out of bounds or invalid memory access must be checked for validity, and the API design together with the type system enforces it.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
pub struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;SpeedTrap,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- VisMod? 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' ColonNAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Script&amp;lt;/code&amp;gt; (with restrictions)&lt;br /&gt;
&lt;br /&gt;
Structs extending game types for player extensions must be declared as &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt;. When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
To read struct objects from script code they must be looked up using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API. Therefore only functions provided with &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt; object (or a context object with contains &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt;) can look up these objects. But you can pass around &amp;lt;code&amp;gt;DB&amp;amp;amp;&amp;lt;/code&amp;gt; as a parameter without any lifetime restrictions, since it’s a purely read only API. This API also works for non-pub structs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= ctx.db.view&amp;amp;lt;Example&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    log(&amp;amp;quot;v = @&amp;amp;quot;, config.v);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;pub-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== pub structs ====&lt;br /&gt;
&lt;br /&gt;
As explained earlier, &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs are the user interface of your scripts. They are exposed in the UI as input forms, and their &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;s can give some control over this rendering. Conceptually they are owned by the player of the game as part of the game object database, by attaching them to a game model object in the database, not the script. Scripts do not have any capability to create, edit or delete objects of &amp;lt;code&amp;gt;pub struct&amp;lt;/code&amp;gt;s. It is always the player who decides when to create a new object of these structs by interacting in the UI. Scripts can then read, and only read, the content of these objects, by using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API presented earlier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs have a very powerful capability: they have limited support for forward schema evolution. This means that the script developer can add to, and reorder, fields in &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, and the game runtime will be able keep the contents of the other fields intact. This is very important to respect the input data by the player. If you rename &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs or their fields, or change their types, the player input data will be lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;non-pub-or-private-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Non-pub (or private) structs ====&lt;br /&gt;
&lt;br /&gt;
Non-&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, also called private structs, are conceptually owned by the script as a part of the simulation, not the player. Their contents are assumed to be a black box by the rest of the game. Scripts are allowed to create and modify objects of these structs during their execution, which are automatically deleted at the end of the simulation frame. It is also possible to attach these structs to existing game model objects to extend their lifetime beyond the current frame. In this case their lifetime becomes the same as the game object, and they can be retrieved in later frames for reading, deleted or overwritten as desired.&lt;br /&gt;
&lt;br /&gt;
Private structs ''do not support schema evolution''. Changing field types, field names, reordering of fields, even just adding new fields at the end, will always result in losing all existing attached objects of the given struct. Some operations like resetting the simulation will also erase attached objects, because they are considered simulation state, not player created objects.&lt;br /&gt;
&lt;br /&gt;
Private structs support dynamic memory allocation. All private struct definitions automatically create a &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; method for the struct:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct PrivData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let ro &amp;amp;amp;= ctx.db.view&amp;amp;lt;PrivData&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    let rw &amp;amp;amp;mut= PrivData::clone(ro);&lt;br /&gt;
    rw.v = 100;&lt;br /&gt;
    let empty &amp;amp;amp;mut= PrivData::new();&lt;br /&gt;
    empty.v = 200;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The objects allocated by &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; are always deleted at the end of the current simulation frame. Their lifetime can be extended beyond the current frame by attaching them to a game object, like &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, so their lifetime becomes the same as the attached object. The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API has methods for attaching and erasing these object.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;host-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Host structs ====&lt;br /&gt;
&lt;br /&gt;
Many of the exposed game APIs are also based around structs. These structs do not follow any of the previous rules. Some have special capabilities, for example simple structs like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt; are ''value objects'': they can be copied and passed around like any &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; would. Some others are strictly locked down and serve as very little beyond a way to keep a pointer safe. In general, when working with game API structs, assume they are what would be called ''move only'' in C++. And NimbyScript has no move operator or semantics, so in essence assume they are immutable, immobile references, except when documented otherwise (like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As an aside, all script declared &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; or not) are also always ''move only'', and always “owned” by some external entity. This is why the APIs for their manipulation are always based on pointers and references, even for private structs. It is not possible to create plain, stack allocated values of script structs, or to use them as fields in structs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version:&lt;br /&gt;
&lt;br /&gt;
* Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
* Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums)&lt;br /&gt;
* For pub structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* For private structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In pub structs these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types. &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; will also display a small list editor. Keep in mind the correct type is &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;Vec&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- 'let' BindBody 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- 'let' BindBody ';'&lt;br /&gt;
BindBody    &amp;amp;lt;- NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' 'let' BindBody BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- ColonNAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere pointer types cannot be dereferenced, therefore cannot be used in dot expressions. The exception is the built-in function &amp;lt;code&amp;gt;is_valid(ptr): bool&amp;lt;/code&amp;gt;, which is usable with any pointer type.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;extensions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Extensions =&lt;br /&gt;
&lt;br /&gt;
Extending game database struct data with &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt; can also be used to extend the game code. The mechanism to do so is to first declare a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;ing a game database object (with or without fields). Then create a specifically named and parametrized function which will be called by the game under certain situations, for certain kinds of objects.&lt;br /&gt;
&lt;br /&gt;
All extension functions take a &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter which is a reference to the struct which it is method of, called &amp;lt;code&amp;gt;Example&amp;lt;/code&amp;gt; in the following sections. Replace it with your struct name. The rest of the parameters are fixed and must be reproduced exactly as-is.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
Event functions are called as part of the core simulation engine. They are meant to be focused in features and quick to execute. These functions might be called thousands of times per simulation frame, including multiple redundant times. Their capability to change the simulation behavior is usually very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_check&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_check ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails, or if another script call returns &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_lookahead&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_lookahead ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_lookahead(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    train_distance: f64,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalLookaheadResult&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; function at regular intervals for each signal 15km ahead of the train path. It is called for all signals, until one of these conditions hold: - One of the signals path checks as &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; - Another train is found - The train stop is found - 15km have been checked&lt;br /&gt;
&lt;br /&gt;
For both &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; signals, your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; will be called, and you can check the path find result in &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;, and the distance from the train in &amp;lt;code&amp;gt;train_distance&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; allows to set a maximum speed for the train, which goes into effect immediately. This works from any distance and past any amount of signals between the train and the caller signal. If multiple signals in the lookahead path return a &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt;, the slowest speed is picked. If no &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt; is set, or it is 0, the result is ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; default value is 0, which is considered invalid and will be ignored. To stop the train at the signal implement &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_change_path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_change_path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_change_path(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The current path check result of this signal for the passed train is passed as &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;. This already includes any results from &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_pass_by&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_pass_by ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_pass_by(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; function on the exact simulation frame a train passes by the exact point of the signal on the track.&lt;br /&gt;
&lt;br /&gt;
This function has no return result. Instead, since it has a predictably low call rate compared to the other events, it is the only event function with access to the powerful &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_marker_reserved&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_marker_reserved ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given marker signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; any time the reservation check algorithm is tracing a path which goes over the marker signal, on any direction, giving it the chance to report an arbitrary train as the reserver of that point on the track.&lt;br /&gt;
&lt;br /&gt;
This signal has a potential huge call rate, and for this reason it is given very little access to the APIs. The intention is that all the state required by this signal is calculated somewhere else and attached to the signal as a private struct object, or to some object reachable from it. Don’t worry about filtering for the “same train” cases, this is automatically done.&lt;br /&gt;
&lt;br /&gt;
If no reservation is desired, use the &amp;lt;code&amp;gt;empty&amp;lt;/code&amp;gt; global method available in all &amp;lt;code&amp;gt;ID&amp;amp;lt;Class&amp;amp;gt;&amp;lt;/code&amp;gt; types: &amp;lt;code&amp;gt;return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {}&lt;br /&gt;
struct Owner {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; {&lt;br /&gt;
    // some other, more full featured script function has attached Owner to this signal,&lt;br /&gt;
    // or not, so we need to check first&lt;br /&gt;
    if let owner &amp;amp;amp;= db.view&amp;amp;lt;Owner&amp;amp;gt;(signal) {&lt;br /&gt;
        if is_valid(db.view(owner.train_id)) {&lt;br /&gt;
            return owner.train_id;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_texture_state&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_texture_state ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_texture_state(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): i64 { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment, when the game UI needs to query what is the current signal texture state index, it will call your &amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt;, with some potential caching to keep the call rate lower. In any case the call rate of this function is potentially very large when the user zooms out the map, so make sure to keep its code as efficient as possible. For this same reason it is given very little access to the APIs.&lt;br /&gt;
&lt;br /&gt;
The return value indicates which signal texture state is to be used. If it’s -1 or lower, the default algorithm will be used to select the texture index. If it’s 0 or larger, it will select the texture in the same order as the &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; lines in the &amp;lt;code&amp;gt;SignalTextures&amp;lt;/code&amp;gt;. Larger values than the number of states will be clamped to the last state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_setup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_setup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_setup(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ss: &amp;amp;amp;mut ShiftSetup&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when an unassigned train decides to lookup a new shift to run, it will first call &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The parameter &amp;lt;code&amp;gt;ss&amp;lt;/code&amp;gt; is both an input and output parameter. It is initialized with the current, relevant data for the given train state, and &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; can then change it, to influence which shifts will be considered by the shift selection algorithm. It can change the train position used for matching, the time used for matching, and disable the check for reservations. For matched shifts which do not correspond to the current train position, the Extrapolator system will automatically pathfind a temporary milestone for the train, like other path-changing features.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_allow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_allow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_allow(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    run: &amp;amp;amp;Run,&lt;br /&gt;
    stop_idx: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    pose: &amp;amp;amp;Pose&lt;br /&gt;
): ShiftAllow { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when the shift selection algorithm fins a valid shift for the given train, it will call &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; with all the relevant data. The return of the function can then allow or deny the shift. If the shift is denied, the algorithm will resume immediately, trying other shifts&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are independent from each other, and can be used in any combination.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;linestop-event_line_stop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Line::Stop event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestStop extend Line::Stop {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestStop::event_line_stop(&lt;br /&gt;
    self: &amp;amp;amp;TestStop,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == LineStopEvent::Arrive {&lt;br /&gt;
        log(&amp;amp;quot;@ arrives @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ departs @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given line stop in the line editor. From that moment, when any train arrives or departs said line stop, &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LineStopEvent::Depart&amp;lt;/code&amp;gt; to distinguish between arrival and departure. Waypoints are only called for &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt;. Shift-less trains are also called.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;shift-event_shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Shift event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestShift extend Shift {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestShift::event_shift(&lt;br /&gt;
    self: &amp;amp;amp;TestShift,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == ShiftEvent::Assign {&lt;br /&gt;
        log(&amp;amp;quot;@ assigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ unassigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given schedule shift in the line editor. From that moment, when any train is assigned to the shift, or becomes unassigned from the shift, &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;ShiftEvent::Assign&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ShiftEvent::Unassign&amp;lt;/code&amp;gt; to distinguish between assignation and unassignation. The &amp;lt;code&amp;gt;Assign&amp;lt;/code&amp;gt; event is called just after &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been set up, so it already has all the shift and run information. The &amp;lt;code&amp;gt;Unassign&amp;lt;/code&amp;gt; event is called just before &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been cleared of all shift and run information so the script has access to as much information as possible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;controllers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Controllers ==&lt;br /&gt;
&lt;br /&gt;
Controller functions are called at a low frame rate compared to the overall simulation, with an (unchangeable) rate of once in 6 sim-seconds. They do not need any specific event or trigger to run, other than their enforced timer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-control_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train control_train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct HateDepots extend Train {}&lt;br /&gt;
pub fn HateDepots::control_train(&lt;br /&gt;
    self: &amp;amp;amp;HateDepots,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    // train is already removed from the tracks, don't interfere with potential attempts at shift assignation&lt;br /&gt;
    if !is_valid(motion.presence.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is running a schedule, don't interfere&lt;br /&gt;
    if is_valid(motion.schedule_dispatch.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is present, but it is not running a schedule, so despawn it&lt;br /&gt;
    sc.queue_train_intervention(train);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The train motion engine will call train controllers in the multithreaded phase, as part of the regular train motion extrapolator, after all the C++ code is done for a frame for a particular train, but before any queued commands are executed. Command execution will only happen after all train controllers for a given frame are done. In other words, train controllers queue up work to be executed by the sim. They never directly change the sim in any way, allowing train controller execution to be fully parallel.&lt;br /&gt;
&lt;br /&gt;
After all controllers are run, and all their non-task commands are executed, and then tasks are executed. Read more about tasks later on. Any tasks with a deadline which expired in this frame a run at this time too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontroller-command-queue&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== SimController command queue ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; object implements an API to control the simulation, including modification of some parameters and behaviors. It is also responsible for attaching and erasing private struct data from game objects, on behalf of scripts. The execution of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; is based on a command queue. Every call queues a command and returns immediately to the script code, without making any changes to the game state. Therefore the game state never changes while the script code is running.&lt;br /&gt;
&lt;br /&gt;
Commands queued from events and &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt; are executed asynchronously, there is no guaranteed order of execution! You must prepare your code and data for this design. For stand alone tasks scripts commands are executed in order and in isolation. You can queue up tasks from event and control scripts when you need to guarantee data consistency beyond “pick a random winner”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_intervention&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_intervention ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks, releases its schedule shift (if any), and deletes and refunds its pax (if any). No other cost other than pax refunds is issued. This function can be used as a general “despawn the train” feature, not just for exceptional circumstances.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_warp&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_warp ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks and repositions it at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, re-pathing it to its currently scheduled destination (if any), and setting its speed to 0. This is basically a train wormhole. The train keeps its shift and pax, if any.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_drive_to&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_drive_to ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Re-paths the train path to end at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, without any changes to its shift or pax (if any). It is possible for any future &amp;lt;code&amp;gt;queue_train_drive_to&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; to reset this path at any point, losing the destination. “Queue” here is used as part of the SimController API semantics, it does not mean the train keeps a queue of positions to reach. If the path is not interrupted and the train reaches &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; it will re-path itself towards its current scheduled stop, if it has any, or brake to a stop if unassigned. If &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; was also in the stop area set for its current scheduled stop it will also brake to stop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_attach&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_attach ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the attachment of the &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) to the &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt;, which must be of one of the following types: &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attached objects can be accessed with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt; at some point in the future. If called from a controller function, the attached object will be accessible after all controller functions are done for a given frame. If called from a task, he attached object will be accessible immediately after the task returns, and before any other task is executed. In other words, tasks are transaction-like, in the sense they view an immutable snapshot of the game state, and any changes they queue are executed before any other task, and then visible from these other tasks.&lt;br /&gt;
&lt;br /&gt;
Attaching an object of a given private struct type when it already exists attached to a &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt; will overwrite it. This is how private data is updated from scripting: by using &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; to copy any existing data, modifying the copy, then calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; to replace the existing data. Therefore it is a good idea to keep your private structs small. Only one instance of a given private struct type can be attached to any particular model object, but you can attach as many different private struct types as you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_erase&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_erase ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the erasure of &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt;, which must obtained using with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt;. Trying to erase temporary objects (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) is ignored. The execution of the queued erase commands is analog to the &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; case. In particular a sequences of attach and erase queued from controllers will produce undefined results (impossible to predict which attach and/or erase wins). For example multiple attach from a controller for the same model_obj and private struct type will implicitly pick a singular “winner” attach, but the script does not have any control over which one. Sequences of attach and erase queued from tasks are strictly ordered and isolated, so they produce consistent results, in the same order they were queued in the task script, without any concurrent changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task-and-simcontrollerqueue_task_at&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task and SimController::queue_task_at ===&lt;br /&gt;
&lt;br /&gt;
These functions are documented in the next section.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;control-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Control tasks ==&lt;br /&gt;
&lt;br /&gt;
Control tasks are a very special kind of command which allows scripts to dynamically queue “future work”, with privileged access to the sim. Scripts with access to &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; can call this function to queue up a task for future script execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; must be of a private struct type which implements &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example { ... }&lt;br /&gt;
pub fn Example::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
For example, a train controller script could decide it needs to delay some decision into a task for data consistency reasons (other controllers are running at the same time), and delegate into a task rather than directly calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ControlTrain extend Train { ... }&lt;br /&gt;
pub fn ControlTrain::control_train(&lt;br /&gt;
    self: &amp;amp;amp;ControlTrain,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    task.train_id = train.id;&lt;br /&gt;
    task.v = some_data_from_somewhere;&lt;br /&gt;
    task.prio = 42; // or something smarter, like from ControlTrain, other objects, etc.&lt;br /&gt;
    sc.queue_task(task);&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
struct Task {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
struct SomeData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
pub fn Task::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    let train &amp;amp;amp;= ctx.db.view(self.train_id) else { return; }&lt;br /&gt;
    if let existing &amp;amp;amp;= ctx.db.view&amp;amp;lt;SomeData&amp;amp;gt;(train) {&lt;br /&gt;
        if existing.prio &amp;amp;gt;= self.prio {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    let data = SomeData::new();&lt;br /&gt;
    data.v = self.v;&lt;br /&gt;
    data.prio = self.prio;&lt;br /&gt;
    sc.queue_attach(train, data);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the previous example, maybe &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; will be called multiple times because multiple &amp;lt;code&amp;gt;ControlTrain::control_train()&amp;lt;/code&amp;gt; instances queued objects of &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;, but each execution will be single threaded, and all its queued &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; commands will be executed just after the call is done and before any other &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; call (for &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; or any other struct type), therefore the algorithm to pick a winner based on an explicit priority works.&lt;br /&gt;
&lt;br /&gt;
As mentioned, task execution is single threaded. The game does not feature a real concurrent database, instead all concurrent access is bespoke and very carefully designed to avoid deadlocks and inconsistencies (this is much faster than a general purpose concurrent database). Scripts also run in this parallel system, but their access to the game state is carefully restricted as explained earlier. But in the end, scripts also need to modify data, and do so in a consistent way. Tasks solve this issue, but do so in the most pessimistic possible way, by being single threaded. Therefore script developers should use them in moderation. Consider the “random winner” semantics of control script queuing first, which are completely free performance wise, before deciding you need a task. It is often the case a concurrent problem reduces to “pick 0 or 1 winners, any winner, but never 2 or more” and the default queue semantics already provide that guarantee for attaching a specific model/private pair.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; is provided with &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt;, therefore it can queue tasks itself. But unlike controller queuing tasks, which are guaranteed to run on the same frame, tasks queued from tasks are guaranteed to ''not'' run on the same frame, on purpose. They are deliberately stored away and forced a delay of 6 sim-seconds. This is to avoid misuse of tasks, and infinite looping.&lt;br /&gt;
&lt;br /&gt;
This behavior might even be desirable in certain scripts, for example if you are developing some stateful signal system and you need some kind of “cleanup” task that makes sure some signal being owned by some train is still the focus of said train. You can deliberately queue tasks for future simulation frames with &amp;lt;code&amp;gt;queue_task_at&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;deadline&amp;lt;/code&amp;gt; is expressed as microseconds since the start of the current save world. You can obtain the current simulation frame &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; value with &amp;lt;code&amp;gt;Extrapolator::clock_us()&amp;lt;/code&amp;gt;, like in this example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;    // schedule task to run 10 sim-s from now&lt;br /&gt;
    sc.queue_task_at(task, ctx.extrapolator.clock_us() + 10000000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;event-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Event tasks ==&lt;br /&gt;
&lt;br /&gt;
Event tasks are a lightweight version of tasks which run when triggered by certain events. Unlike control tasks, event tasks do not have unlimited access to the sim. Instead the run under an &amp;lt;code&amp;gt;EventCtx&amp;lt;/code&amp;gt; like pub struct events, and run multithreaded, at the same time as the C++ code. Unlike the regular &amp;lt;code&amp;gt;event_*&amp;lt;/code&amp;gt; methods, event tasks are queued for execution by script code, not by UI player commands. The design idea of these tasks is to offer a more focused and efficient execution model than &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt;: they are executed immediately once the relevant event happens, in multithreaded context, rather than require passive polling which might even miss certain events and force execution of single thread code.&lt;br /&gt;
&lt;br /&gt;
Any function with a &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; parameter can queue an even task like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Task {...}&lt;br /&gt;
fn f(..., train: &amp;amp;amp;Train, sc: &amp;amp;amp;mut SimController) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    sc.queue_task_event_train(task, train, TaskEventTrain::StopDepart);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
On the next stop departure of the train the &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt; method will be called:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn Task::task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: TaskEventTrain,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == TaskEventTrain::StopDepart {&lt;br /&gt;
        log(&amp;amp;quot;@ departs&amp;amp;quot;, train);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Like control tasks, event tasks encapsulate a single call. If a series of calls are desired, the task can requeue itself by calling &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt;. Event tasks are limited to a maximum of 1 for every possible train-struct-event combination, to avoid leaks. Trying to queue again the same train-struct-event combination will overwrite any existing task. Only the train and motion are provided as parameters. The code can then drill into motion to extract any required information, like shift or line.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-controlctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ControlCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ControlCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    sim: &amp;amp;amp;Sim,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim controller scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects, and associated script stuct objects.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::track_pos_project(self: &amp;amp;amp;DB, pos: &amp;amp;amp;Pos, distance: f64): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return a track position separated by ‘distance’ meters from ‘pos’, in the direction of ‘pos’. If distance is negative it will be in the opposite direction. Can only follow the main track. Merges and dead ends will return a Pos a shorter distance away. Signals are ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB): &amp;amp;amp;Script&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-eventctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type EventCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct EventCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim event handler scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line::Stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line::Stop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    station_stop: std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;,&lt;br /&gt;
    run_stop: std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
    run_dispatch: std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;,&lt;br /&gt;
    hitch: std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionhitch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Hitch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Hitch {&lt;br /&gt;
    driver_train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Train is being hitched by a driver train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionrundispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::RunDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::RunDispatch {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a line run.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Motion::RunDispatch::current_stop(self: &amp;amp;amp;Motion::RunDispatch, line: &amp;amp;amp;Line): *Line::Stop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionstationstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::StationStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::StationStop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Schedule::view(self: &amp;amp;amp;Schedule, shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;): *Shift&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns a pointer to the shift, if it’s contained in this schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-script&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Script ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Script {&lt;br /&gt;
    id: ID&amp;amp;lt;Script&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Shift {&lt;br /&gt;
    id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::kind(self: &amp;amp;amp;Signal): mut SignalKind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the signal kind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Hitch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;): *Motion::Hitch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStationEvent&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;&lt;br /&gt;
): *Motion::StationStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Script&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Shift&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Shift&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Shift&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::clock_us(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current microseconds since the creation of this saved game. This is used as the timing root of the simulation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second since 1970-01-01:00:00:00.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_occupation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_reservation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying or reserving the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_occupying(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_reserving(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying or reserving the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
Probe a track position for train reservations and occupations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Seconds since 1970-01-01:00:00:00 for Monday 00:00:00 of the current week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestopevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type LineStopEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum LineStopEvent {&lt;br /&gt;
    Arrive,&lt;br /&gt;
    Depart,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
Advance the iterator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftallow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftAllow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftAllow {&lt;br /&gt;
    Allow,&lt;br /&gt;
    Deny,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftEvent {&lt;br /&gt;
    Assign,&lt;br /&gt;
    Unassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftsetup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftSetup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ShiftSetup {&lt;br /&gt;
    skip: bool,&lt;br /&gt;
    match_pos: bool,&lt;br /&gt;
    check_occupation: bool,&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores the context of a train shift lookup.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function wants to change the train path, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signallookaheadresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalLookaheadResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalLookaheadResult {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores extra information associated with the result of the signal lookahead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-sim&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Sim ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Sim {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of the simulation state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Sim::view&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Sim, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A proxy mutable API to the simulation engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    ev: TaskEventTrain&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_hitch(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    driver: &amp;amp;amp;Train,&lt;br /&gt;
    hitcher: &amp;amp;amp;Train&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(self: &amp;amp;amp;mut SimController, train: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_run_line(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    arrival_offset_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_configuration(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    config: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_unhitch(self: &amp;amp;amp;mut SimController, hitcher: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-taskeventtrain&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TaskEventTrain ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum TaskEventTrain {&lt;br /&gt;
    StopArrive,&lt;br /&gt;
    StopDepart,&lt;br /&gt;
    ShiftAssign,&lt;br /&gt;
    ShiftUnassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=552</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=552"/>
		<updated>2025-12-26T16:53:23Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used in game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration, integer division or arbitrary setting of pointers and references, and most data exposed to scripts is read-only, strictly enforced by the language. Any expression result which could result in an out of bounds or invalid memory access must be checked for validity, and the API design together with the type system enforces it.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
pub struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;SpeedTrap,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- VisMod? 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' ColonNAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Script&amp;lt;/code&amp;gt; (with restrictions)&lt;br /&gt;
&lt;br /&gt;
Structs extending game types for player extensions must be declared as &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt;. When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
To read struct objects from script code they must be looked up using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API. Therefore only functions provided with &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt; object (or a context object with contains &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt;) can look up these objects. But you can pass around &amp;lt;code&amp;gt;DB&amp;amp;amp;&amp;lt;/code&amp;gt; as a parameter without any lifetime restrictions, since it’s a purely read only API. This API also works for non-pub structs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= ctx.db.view&amp;amp;lt;Example&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    log(&amp;amp;quot;v = @&amp;amp;quot;, config.v);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;pub-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== pub structs ====&lt;br /&gt;
&lt;br /&gt;
As explained earlier, &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs are the user interface of your scripts. They are exposed in the UI as input forms, and their &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;s can give some control over this rendering. Conceptually they are owned by the player of the game as part of the game object database, by attaching them to a game model object in the database, not the script. Scripts do not have any capability to create, edit or delete objects of &amp;lt;code&amp;gt;pub struct&amp;lt;/code&amp;gt;s. It is always the player who decides when to create a new object of these structs by interacting in the UI. Scripts can then read, and only read, the content of these objects, by using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API presented earlier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs have a very powerful capability: they have limited support for forward schema evolution. This means that the script developer can add to, and reorder, fields in &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, and the game runtime will be able keep the contents of the other fields intact. This is very important to respect the input data by the player. If you rename &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs or their fields, or change their types, the player input data will be lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;non-pub-or-private-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Non-pub (or private) structs ====&lt;br /&gt;
&lt;br /&gt;
Non-&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, also called private structs, are conceptually owned by the script as a part of the simulation, not the player. Their contents are assumed to be a black box by the rest of the game. Scripts are allowed to create and modify objects of these structs during their execution, which are automatically deleted at the end of the simulation frame. It is also possible to attach these structs to existing game model objects to extend their lifetime beyond the current frame. In this case their lifetime becomes the same as the game object, and they can be retrieved in later frames for reading, deleted or overwritten as desired.&lt;br /&gt;
&lt;br /&gt;
Private structs ''do not support schema evolution''. Changing field types, field names, reordering of fields, even just adding new fields at the end, will always result in losing all existing attached objects of the given struct. Some operations like resetting the simulation will also erase attached objects, because they are considered simulation state, not player created objects.&lt;br /&gt;
&lt;br /&gt;
Private structs support dynamic memory allocation. All private struct definitions automatically create a &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; method for the struct:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct PrivData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let ro &amp;amp;amp;= ctx.db.view&amp;amp;lt;PrivData&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    let rw &amp;amp;amp;mut= PrivData::clone(ro);&lt;br /&gt;
    rw.v = 100;&lt;br /&gt;
    let empty &amp;amp;amp;mut= PrivData::new();&lt;br /&gt;
    empty.v = 200;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The objects allocated by &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; are always deleted at the end of the current simulation frame. Their lifetime can be extended beyond the current frame by attaching them to a game object, like &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, so their lifetime becomes the same as the attached object. The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API has methods for attaching and erasing these object.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;host-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Host structs ====&lt;br /&gt;
&lt;br /&gt;
Many of the exposed game APIs are also based around structs. These structs do not follow any of the previous rules. Some have special capabilities, for example simple structs like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt; are ''value objects'': they can be copied and passed around like any &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; would. Some others are strictly locked down and serve as very little beyond a way to keep a pointer safe. In general, when working with game API structs, assume they are what would be called ''move only'' in C++. And NimbyScript has no move operator or semantics, so in essence assume they are immutable, immobile references, except when documented otherwise (like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As an aside, all script declared &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; or not) are also always ''move only'', and always “owned” by some external entity. This is why the APIs for their manipulation are always based on pointers and references, even for private structs. It is not possible to create plain, stack allocated values of script structs, or to use them as fields in structs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version:&lt;br /&gt;
&lt;br /&gt;
* Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
* Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums)&lt;br /&gt;
* For pub structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* For private structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In pub structs these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types. &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; will also display a small list editor. Keep in mind the correct type is &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;Vec&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- 'let' BindBody 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- 'let' BindBody ';'&lt;br /&gt;
BindBody    &amp;amp;lt;- NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' 'let' BindBody BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- ColonNAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere pointer types cannot be dereferenced, therefore cannot be used in dot expressions. The exception is the built-in function &amp;lt;code&amp;gt;is_valid(ptr): bool&amp;lt;/code&amp;gt;, which is usable with any pointer type.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;extensions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Extensions =&lt;br /&gt;
&lt;br /&gt;
Extending game database struct data with &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt; can also be used to extend the game code. The mechanism to do so is to first declare a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;ing a game database object (with or without fields). Then create a specifically named and parametrized function which will be called by the game under certain situations, for certain kinds of objects.&lt;br /&gt;
&lt;br /&gt;
All extension functions take a &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter which is a reference to the struct which it is method of, called &amp;lt;code&amp;gt;Example&amp;lt;/code&amp;gt; in the following sections. Replace it with your struct name. The rest of the parameters are fixed and must be reproduced exactly as-is.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
Event functions are called as part of the core simulation engine. They are meant to be focused in features and quick to execute. These functions might be called thousands of times per simulation frame, including multiple redundant times. Their capability to change the simulation behavior is usually very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_check&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_check ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails, or if another script call returns &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_lookahead&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_lookahead ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_lookahead(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    train_distance: f64,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalLookaheadResult&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; function at regular intervals for each signal 15km ahead of the train path. It is called for all signals, until one of these conditions hold: - One of the signals path checks as &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; - Another train is found - The train stop is found - 15km have been checked&lt;br /&gt;
&lt;br /&gt;
For both &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; signals, your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; will be called, and you can check the path find result in &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;, and the distance from the train in &amp;lt;code&amp;gt;train_distance&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; allows to set a maximum speed for the train, which goes into effect immediately. This works from any distance and past any amount of signals between the train and the caller signal. If multiple signals in the lookahead path return a &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt;, the slowest speed is picked. If no &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt; is set, or it is 0, the result is ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; default value is 0, which is considered invalid and will be ignored. To stop the train at the signal implement &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_change_path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_change_path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_change_path(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The current path check result of this signal for the passed train is passed as &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;. This already includes any results from &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_pass_by&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_pass_by ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_pass_by(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; function on the exact simulation frame a train passes by the exact point of the signal on the track.&lt;br /&gt;
&lt;br /&gt;
This function has no return result. Instead, since it has a predictably low call rate compared to the other events, it is the only event function with access to the powerful &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_marker_reserved&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_marker_reserved ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given marker signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; any time the reservation check algorithm is tracing a path which goes over the marker signal, on any direction, giving it the chance to report an arbitrary train as the reserver of that point on the track.&lt;br /&gt;
&lt;br /&gt;
This signal has a potential huge call rate, and for this reason it is given very little access to the APIs. The intention is that all the state required by this signal is calculated somewhere else and attached to the signal as a private struct object, or to some object reachable from it. Don’t worry about filtering for the “same train” cases, this is automatically done.&lt;br /&gt;
&lt;br /&gt;
If no reservation is desired, use the &amp;lt;code&amp;gt;empty&amp;lt;/code&amp;gt; global method available in all &amp;lt;code&amp;gt;ID&amp;amp;lt;Class&amp;amp;gt;&amp;lt;/code&amp;gt; types: &amp;lt;code&amp;gt;return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {}&lt;br /&gt;
struct Owner {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; {&lt;br /&gt;
    // some other, more full featured script function has attached Owner to this signal,&lt;br /&gt;
    // or not, so we need to check first&lt;br /&gt;
    if let owner &amp;amp;amp;= db.view&amp;amp;lt;Owner&amp;amp;gt;(signal) {&lt;br /&gt;
        if is_valid(db.view(owner.train_id)) {&lt;br /&gt;
            return owner.train_id;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_texture_state&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_texture_state ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_texture_state(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): i64 { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment, when the game UI needs to query what is the current signal texture state index, it will call your &amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt;, with some potential caching to keep the call rate lower. In any case the call rate of this function is potentially very large when the user zooms out the map, so make sure to keep its code as efficient as possible. For this same reason it is given very little access to the APIs.&lt;br /&gt;
&lt;br /&gt;
The return value indicates which signal texture state is to be used. If it’s -1 or lower, the default algorithm will be used to select the texture index. If it’s 0 or larger, it will select the texture in the same order as the &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; lines in the &amp;lt;code&amp;gt;SignalTextures&amp;lt;/code&amp;gt;. Larger values than the number of states will be clamped to the last state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_setup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_setup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_setup(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ss: &amp;amp;amp;mut ShiftSetup&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when an unassigned train decides to lookup a new shift to run, it will first call &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The parameter &amp;lt;code&amp;gt;ss&amp;lt;/code&amp;gt; is both an input and output parameter. It is initialized with the current, relevant data for the given train state, and &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; can then change it, to influence which shifts will be considered by the shift selection algorithm. It can change the train position used for matching, the time used for matching, and disable the check for reservations. For matched shifts which do not correspond to the current train position, the Extrapolator system will automatically pathfind a temporary milestone for the train, like other path-changing features.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_allow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_allow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_allow(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    run: &amp;amp;amp;Run,&lt;br /&gt;
    stop_idx: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    pose: &amp;amp;amp;Pose&lt;br /&gt;
): ShiftAllow { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when the shift selection algorithm fins a valid shift for the given train, it will call &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; with all the relevant data. The return of the function can then allow or deny the shift. If the shift is denied, the algorithm will resume immediately, trying other shifts&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are independent from each other, and can be used in any combination.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;linestop-event_line_stop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Line::Stop event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestStop extend Line::Stop {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestStop::event_line_stop(&lt;br /&gt;
    self: &amp;amp;amp;TestStop,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == LineStopEvent::Arrive {&lt;br /&gt;
        log(&amp;amp;quot;@ arrives @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ departs @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given line stop in the line editor. From that moment, when any train arrives or departs said line stop, &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LineStopEvent::Depart&amp;lt;/code&amp;gt; to distinguish between arrival and departure. Waypoints are only called for &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt;. Shift-less trains are also called.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;shift-event_shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Shift event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestShift extend Shift {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestShift::event_shift(&lt;br /&gt;
    self: &amp;amp;amp;TestShift,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == ShiftEvent::Assign {&lt;br /&gt;
        log(&amp;amp;quot;@ assigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ unassigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given schedule shift in the line editor. From that moment, when any train is assigned to the shift, or becomes unassigned from the shift, &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;ShiftEvent::Assign&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ShiftEvent::Unassign&amp;lt;/code&amp;gt; to distinguish between assignation and unassignation. The &amp;lt;code&amp;gt;Assign&amp;lt;/code&amp;gt; event is called just after &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been set up, so it already has all the shift and run information. The &amp;lt;code&amp;gt;Unassign&amp;lt;/code&amp;gt; event is called just before &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been cleared of all shift and run information so the script has access to as much information as possible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;controllers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Controllers ==&lt;br /&gt;
&lt;br /&gt;
Controller functions are called at a low frame rate compared to the overall simulation, with an (unchangeable) rate of once in 6 sim-seconds. In exchange they can invoke powerful ''commands'' as their execution result, and do not need any specific event or trigger to run, other than their enforced timer&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-control_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train control_train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct HateDepots extend Train {}&lt;br /&gt;
pub fn HateDepots::control_train(&lt;br /&gt;
    self: &amp;amp;amp;HateDepots,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    // train is already removed from the tracks, don't interfere with potential attempts at shift assignation&lt;br /&gt;
    if !is_valid(motion.presence.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is running a schedule, don't interfere&lt;br /&gt;
    if is_valid(motion.schedule_dispatch.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is present, but it is not running a schedule, so despawn it&lt;br /&gt;
    sc.queue_train_intervention(train);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The train motion engine will call train controllers after the entire simulation for a given frame is done, and all threads are finished. Command execution will only happen after all train controllers for a given frame are done. In other words, train controllers are given a consistent, read-only snapshot of the train sim, and queue up work to be executed by the sim. They never directly change the sim in any way, allowing train controller execution to be fully parallel.&lt;br /&gt;
&lt;br /&gt;
After all controllers are run, and all their non-task commands are executed, tasks are executed. Read more about tasks later on. Any tasks with a deadline which expired in this frame a run at this time too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontroller-command-queue&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== SimController command queue ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; object implements an API to control the simulation, including modification of some parameters and behaviors. It is also responsible for attaching and erasing private struct data from game objects, on behalf of scripts. The execution of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; is based on a command queue. Every call queues a command and returns immediately to the script code, without making any changes to the game state. Therefore the game state never changes while the script code is running.&lt;br /&gt;
&lt;br /&gt;
For control scripts, commands are executed asynchronously, there is no guaranteed order of execution! You must prepare your code and data for this design. For tasks scripts commands are executed in order and in isolation. You can queue up tasks from control scripts when you need to guarantee data consistency beyond “pick a random winner”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_intervention&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_intervention ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks, releases its schedule shift (if any), and deletes and refunds its pax (if any). No other cost other than pax refunds is issued. This function can be used as a general “despawn the train” feature, not just for exceptional circumstances.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_warp&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_warp ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks and repositions it at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, re-pathing it to its currently scheduled destination (if any), and setting its speed to 0. This is basically a train wormhole. The train keeps its shift and pax, if any.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_drive_to&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_drive_to ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Re-paths the train path to end at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, without any changes to its shift or pax (if any). It is possible for any future &amp;lt;code&amp;gt;queue_train_drive_to&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; to reset this path at any point, losing the destination. “Queue” here is used as part of the SimController API semantics, it does not mean the train keeps a queue of positions to reach. If the path is not interrupted and the train reaches &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; it will re-path itself towards its current scheduled stop, if it has any, or brake to a stop if unassigned. If &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; was also in the stop area set for its current scheduled stop it will also brake to stop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_attach&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_attach ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the attachment of the &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) to the &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt;, which must be of one of the following types: &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attached objects can be accessed with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt; at some point in the future. If called from a controller function, the attached object will be accessible after all controller functions are done for a given frame. If called from a task, he attached object will be accessible immediately after the task returns, and before any other task is executed. In other words, tasks are transaction-like, in the sense they view an immutable snapshot of the game state, and any changes they queue are executed before any other task, and then visible from these other tasks.&lt;br /&gt;
&lt;br /&gt;
Attaching an object of a given private struct type when it already exists attached to a &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt; will overwrite it. This is how private data is updated from scripting: by using &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; to copy any existing data, modifying the copy, then calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; to replace the existing data. Therefore it is a good idea to keep your private structs small. Only one instance of a given private struct type can be attached to any particular model object, but you can attach as many different private struct types as you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_erase&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_erase ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the erasure of &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt;, which must obtained using with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt;. Trying to erase temporary objects (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) is ignored. The execution of the queued erase commands is analog to the &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; case. In particular a sequences of attach and erase queued from controllers will produce undefined results (impossible to predict which attach and/or erase wins). For example multiple attach from a controller for the same model_obj and private struct type will implicitly pick a singular “winner” attach, but the script does not have any control over which one. Sequences of attach and erase queued from tasks are strictly ordered and isolated, so they produce consistent results, in the same order they were queued in the task script, without any concurrent changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task-and-simcontrollerqueue_task_at&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task and SimController::queue_task_at ===&lt;br /&gt;
&lt;br /&gt;
These functions are documented in the next section.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;control-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Control tasks ==&lt;br /&gt;
&lt;br /&gt;
Control tasks are a very special kind of command which allows scripts to dynamically queue “future work”, with privileged access to the sim. Scripts with access to &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; can call this function to queue up a task for future script execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; must be of a private struct type which implements &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example { ... }&lt;br /&gt;
pub fn Example::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
For example, a train controller script could decide it needs to delay some decision into a task for data consistency reasons (other controllers are running at the same time), and delegate into a task rather than directly calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ControlTrain extend Train { ... }&lt;br /&gt;
pub fn ControlTrain::control_train(&lt;br /&gt;
    self: &amp;amp;amp;ControlTrain,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    task.train_id = train.id;&lt;br /&gt;
    task.v = some_data_from_somewhere;&lt;br /&gt;
    task.prio = 42; // or something smarter, like from ControlTrain, other objects, etc.&lt;br /&gt;
    sc.queue_task(task);&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
struct Task {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
struct SomeData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
pub fn Task::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    let train &amp;amp;amp;= ctx.db.view(self.train_id) else { return; }&lt;br /&gt;
    if let existing &amp;amp;amp;= ctx.db.view&amp;amp;lt;SomeData&amp;amp;gt;(train) {&lt;br /&gt;
        if existing.prio &amp;amp;gt;= self.prio {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    let data = SomeData::new();&lt;br /&gt;
    data.v = self.v;&lt;br /&gt;
    data.prio = self.prio;&lt;br /&gt;
    sc.queue_attach(train, data);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the previous example, maybe &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; will be called multiple times because multiple &amp;lt;code&amp;gt;ControlTrain::control_train()&amp;lt;/code&amp;gt; instances queued objects of &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;, but each execution will be single threaded, and all its queued &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; commands will be executed just after the call is done and before any other &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; call (for &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; or any other struct type), therefore the algorithm to pick a winner based on an explicit priority works.&lt;br /&gt;
&lt;br /&gt;
As mentioned, task execution is single threaded. The game does not feature a real concurrent database, instead all concurrent access is bespoke and very carefully designed to avoid deadlocks and inconsistencies (this is much faster than a general purpose concurrent database). Scripts also run in this parallel system, but their access to the game state is carefully restricted as explained earlier. But in the end, scripts also need to modify data, and do so in a consistent way. Tasks solve this issue, but do so in the most pessimistic possible way, by being single threaded. Therefore script developers should use them in moderation. Consider the “random winner” semantics of control script queuing first, which are completely free performance wise, before deciding you need a task. It is often the case a concurrent problem reduces to “pick 0 or 1 winners, any winner, but never 2 or more” and the default queue semantics already provide that guarantee for attaching a specific model/private pair.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; is provided with &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt;, therefore it can queue tasks itself. But unlike controller queuing tasks, which are guaranteed to run on the same frame, tasks queued from tasks are guaranteed to ''not'' run on the same frame, on purpose. They are deliberately stored away and forced a delay of 6 sim-seconds. This is to avoid misuse of tasks, and infinite looping.&lt;br /&gt;
&lt;br /&gt;
This behavior might even be desirable in certain scripts, for example if you are developing some stateful signal system and you need some kind of “cleanup” task that makes sure some signal being owned by some train is still the focus of said train. You can deliberately queue tasks for future simulation frames with &amp;lt;code&amp;gt;queue_task_at&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;deadline&amp;lt;/code&amp;gt; is expressed as microseconds since the start of the current save world. You can obtain the current simulation frame &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; value with &amp;lt;code&amp;gt;Extrapolator::clock_us()&amp;lt;/code&amp;gt;, like in this example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;    // schedule task to run 10 sim-s from now&lt;br /&gt;
    sc.queue_task_at(task, ctx.extrapolator.clock_us() + 10000000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;event-tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Event tasks ==&lt;br /&gt;
&lt;br /&gt;
Event tasks are a lightweight version of tasks which run when triggered by certain events. Unlike control tasks, event tasks do not have unlimited access to the sim. Instead the run under an &amp;lt;code&amp;gt;EventCtx&amp;lt;/code&amp;gt; like pub struct events, and run multithreaded, at the same time as the C++ code. Unlike the regular &amp;lt;code&amp;gt;event_*&amp;lt;/code&amp;gt; methods, event tasks are queued for execution by script code, not by UI player commands. The design idea of these tasks is to offer a more focused and efficient execution model than &amp;lt;code&amp;gt;control_train&amp;lt;/code&amp;gt;: they are executed immediately once the relevant event happens, in multithreaded context, rather than require passive polling which might even miss certain events and force execution of single thread code.&lt;br /&gt;
&lt;br /&gt;
Any function with a &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; parameter can queue an even task like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Task {...}&lt;br /&gt;
fn f(..., train: &amp;amp;amp;Train, sc: &amp;amp;amp;mut SimController) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    sc.queue_task_event_train(task, train, TaskEventTrain::StopDepart);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
On the next stop departure of the train the &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt; method will be called:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub fn Task::task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: TaskEventTrain,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == TaskEventTrain::StopDepart {&lt;br /&gt;
        log(&amp;amp;quot;@ departs&amp;amp;quot;, train);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Like control tasks, event tasks encapsulate a single call. If a series of calls are desired, the task can requeue itself by calling &amp;lt;code&amp;gt;Task::task_event_train&amp;lt;/code&amp;gt;. Event tasks are limited to a maximum of 1 for every possible train-struct-event combination, to avoid leaks. Trying to queue again the same train-struct-event combination will overwrite any existing task. Only the train and motion are provided as parameters. The code can then drill into motion to extract any required information, like shift or line.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-controlctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ControlCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ControlCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    sim: &amp;amp;amp;Sim,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim controller scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects, and associated script stuct objects.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::track_pos_project(self: &amp;amp;amp;DB, pos: &amp;amp;amp;Pos, distance: f64): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return a track position separated by ‘distance’ meters from ‘pos’, in the direction of ‘pos’. If distance is negative it will be in the opposite direction. Can only follow the main track. Merges and dead ends will return a Pos a shorter distance away. Signals are ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB): &amp;amp;amp;Script&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-eventctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type EventCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct EventCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim event handler scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line::Stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line::Stop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    station_stop: std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;,&lt;br /&gt;
    run_stop: std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
    run_dispatch: std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;,&lt;br /&gt;
    hitch: std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionhitch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Hitch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Hitch {&lt;br /&gt;
    driver_train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Train is being hitched by a driver train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionrundispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::RunDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::RunDispatch {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a line run.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Motion::RunDispatch::current_stop(self: &amp;amp;amp;Motion::RunDispatch, line: &amp;amp;amp;Line): *Line::Stop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionstationstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::StationStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::StationStop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Schedule::view(self: &amp;amp;amp;Schedule, shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;): *Shift&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns a pointer to the shift, if it’s contained in this schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-script&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Script ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Script {&lt;br /&gt;
    id: ID&amp;amp;lt;Script&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Shift {&lt;br /&gt;
    id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::kind(self: &amp;amp;amp;Signal): mut SignalKind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the signal kind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Hitch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;): *Motion::Hitch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStationEvent&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;&lt;br /&gt;
): *Motion::StationStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Script&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Shift&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Shift&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Shift&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::clock_us(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current microseconds since the creation of this saved game. This is used as the timing root of the simulation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second since 1970-01-01:00:00:00.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_occupation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_reservation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying or reserving the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_occupying(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_reserving(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying or reserving the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
Probe a track position for train reservations and occupations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Seconds since 1970-01-01:00:00:00 for Monday 00:00:00 of the current week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestopevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type LineStopEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum LineStopEvent {&lt;br /&gt;
    Arrive,&lt;br /&gt;
    Depart,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
Advance the iterator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftallow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftAllow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftAllow {&lt;br /&gt;
    Allow,&lt;br /&gt;
    Deny,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftEvent {&lt;br /&gt;
    Assign,&lt;br /&gt;
    Unassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftsetup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftSetup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ShiftSetup {&lt;br /&gt;
    skip: bool,&lt;br /&gt;
    match_pos: bool,&lt;br /&gt;
    check_occupation: bool,&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores the context of a train shift lookup.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function wants to change the train path, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signallookaheadresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalLookaheadResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalLookaheadResult {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores extra information associated with the result of the signal lookahead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-sim&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Sim ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Sim {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of the simulation state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Sim::view&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Sim, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A proxy mutable API to the simulation engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_event_train(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    ev: TaskEventTrain&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_hitch(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    driver: &amp;amp;amp;Train,&lt;br /&gt;
    hitcher: &amp;amp;amp;Train&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(self: &amp;amp;amp;mut SimController, train: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_run_line(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    arrival_offset_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_configuration(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    config: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_unhitch(self: &amp;amp;amp;mut SimController, hitcher: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-taskeventtrain&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TaskEventTrain ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum TaskEventTrain {&lt;br /&gt;
    StopArrive,&lt;br /&gt;
    StopDepart,&lt;br /&gt;
    ShiftAssign,&lt;br /&gt;
    ShiftUnassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=551</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=551"/>
		<updated>2025-12-22T11:56:57Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used in game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration, integer division or arbitrary setting of pointers and references, and most data exposed to scripts is read-only, strictly enforced by the language. Any expression result which could result in an out of bounds or invalid memory access must be checked for validity, and the API design together with the type system enforces it.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
pub struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;SpeedTrap,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- VisMod? 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' ColonNAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Script&amp;lt;/code&amp;gt; (with restrictions)&lt;br /&gt;
&lt;br /&gt;
Structs extending game types for player extensions must be declared as &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt;. When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
To read struct objects from script code they must be looked up using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API. Therefore only functions provided with &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt; object (or a context object with contains &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt;) can look up these objects. But you can pass around &amp;lt;code&amp;gt;DB&amp;amp;amp;&amp;lt;/code&amp;gt; as a parameter without any lifetime restrictions, since it’s a purely read only API. This API also works for non-pub structs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= ctx.db.view&amp;amp;lt;Example&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    log(&amp;amp;quot;v = @&amp;amp;quot;, config.v);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;pub-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== pub structs ====&lt;br /&gt;
&lt;br /&gt;
As explained earlier, &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs are the user interface of your scripts. They are exposed in the UI as input forms, and their &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;s can give some control over this rendering. Conceptually they are owned by the player of the game as part of the game object database, by attaching them to a game model object in the database, not the script. Scripts do not have any capability to create, edit or delete objects of &amp;lt;code&amp;gt;pub struct&amp;lt;/code&amp;gt;s. It is always the player who decides when to create a new object of these structs by interacting in the UI. Scripts can then read, and only read, the content of these objects, by using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API presented earlier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs have a very powerful capability: they have limited support for forward schema evolution. This means that the script developer can add to, and reorder, fields in &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, and the game runtime will be able keep the contents of the other fields intact. This is very important to respect the input data by the player. If you rename &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs or their fields, or change their types, the player input data will be lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;non-pub-or-private-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Non-pub (or private) structs ====&lt;br /&gt;
&lt;br /&gt;
Non-&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, also called private structs, are conceptually owned by the script as a part of the simulation, not the player. Their contents are assumed to be a black box by the rest of the game. Scripts are allowed to create and modify objects of these structs during their execution, which are automatically deleted at the end of the simulation frame. It is also possible to attach these structs to existing game model objects to extend their lifetime beyond the current frame. In this case their lifetime becomes the same as the game object, and they can be retrieved in later frames for reading, deleted or overwritten as desired.&lt;br /&gt;
&lt;br /&gt;
Private structs ''do not support schema evolution''. Changing field types, field names, reordering of fields, even just adding new fields at the end, will always result in losing all existing attached objects of the given struct. Some operations like resetting the simulation will also erase attached objects, because they are considered simulation state, not player created objects.&lt;br /&gt;
&lt;br /&gt;
Private structs support dynamic memory allocation. All private struct definitions automatically create a &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; method for the struct:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct PrivData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let ro &amp;amp;amp;= ctx.db.view&amp;amp;lt;PrivData&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    let rw &amp;amp;amp;mut= PrivData::clone(ro);&lt;br /&gt;
    rw.v = 100;&lt;br /&gt;
    let empty &amp;amp;amp;mut= PrivData::new();&lt;br /&gt;
    empty.v = 200;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The objects allocated by &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; are always deleted at the end of the current simulation frame. Their lifetime can be extended beyond the current frame by attaching them to a game object, like &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, so their lifetime becomes the same as the attached object. The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API has methods for attaching and erasing these object.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;host-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Host structs ====&lt;br /&gt;
&lt;br /&gt;
Many of the exposed game APIs are also based around structs. These structs do not follow any of the previous rules. Some have special capabilities, for example simple structs like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt; are ''value objects'': they can be copied and passed around like any &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; would. Some others are strictly locked down and serve as very little beyond a way to keep a pointer safe. In general, when working with game API structs, assume they are what would be called ''move only'' in C++. And NimbyScript has no move operator or semantics, so in essence assume they are immutable, immobile references, except when documented otherwise (like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As an aside, all script declared &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; or not) are also always ''move only'', and always “owned” by some external entity. This is why the APIs for their manipulation are always based on pointers and references, even for private structs. It is not possible to create plain, stack allocated values of script structs, or to use them as fields in structs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version:&lt;br /&gt;
&lt;br /&gt;
* Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
* Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums)&lt;br /&gt;
* For pub structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* For private structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In pub structs these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types. &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; will also display a small list editor. Keep in mind the correct type is &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;Vec&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- 'let' BindBody 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- 'let' BindBody ';'&lt;br /&gt;
BindBody    &amp;amp;lt;- NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' 'let' BindBody BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- ColonNAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere pointer types cannot be dereferenced, therefore cannot be used in dot expressions. The exception is the built-in function &amp;lt;code&amp;gt;is_valid(ptr): bool&amp;lt;/code&amp;gt;, which is usable with any pointer type.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;extensions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Extensions =&lt;br /&gt;
&lt;br /&gt;
Extending game database struct data with &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt; can also be used to extend the game code. The mechanism to do so is to first declare a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;ing a game database object (with or without fields). Then create a specifically named and parametrized function which will be called by the game under certain situations, for certain kinds of objects.&lt;br /&gt;
&lt;br /&gt;
All extension functions take a &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter which is a reference to the struct which it is method of, called &amp;lt;code&amp;gt;Example&amp;lt;/code&amp;gt; in the following sections. Replace it with your struct name. The rest of the parameters are fixed and must be reproduced exactly as-is.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
Event functions are called as part of the core simulation engine. They are meant to be focused in features and quick to execute. These functions might be called thousands of times per simulation frame, including multiple redundant times. Their capability to change the simulation behavior is usually very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_check&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_check ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails, or if another script call returns &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_lookahead&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_lookahead ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_lookahead(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    train_distance: f64,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalLookaheadResult&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; function at regular intervals for each signal 15km ahead of the train path. It is called for all signals, until one of these conditions hold: - One of the signals path checks as &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; - Another train is found - The train stop is found - 15km have been checked&lt;br /&gt;
&lt;br /&gt;
For both &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; signals, your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; will be called, and you can check the path find result in &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;, and the distance from the train in &amp;lt;code&amp;gt;train_distance&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; allows to set a maximum speed for the train, which goes into effect immediately. This works from any distance and past any amount of signals between the train and the caller signal. If multiple signals in the lookahead path return a &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt;, the slowest speed is picked. If no &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt; is set, or it is 0, the result is ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; default value is 0, which is considered invalid and will be ignored. To stop the train at the signal implement &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_change_path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_change_path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_change_path(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The current path check result of this signal for the passed train is passed as &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;. This already includes any results from &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_pass_by&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_pass_by ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_pass_by(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; function on the exact simulation frame a train passes by the exact point of the signal on the track.&lt;br /&gt;
&lt;br /&gt;
This function has no return result. Instead, since it has a predictably low call rate compared to the other events, it is the only event function with access to the powerful &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_marker_reserved&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_marker_reserved ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given marker signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; any time the reservation check algorithm is tracing a path which goes over the marker signal, on any direction, giving it the chance to report an arbitrary train as the reserver of that point on the track.&lt;br /&gt;
&lt;br /&gt;
This signal has a potential huge call rate, and for this reason it is given very little access to the APIs. The intention is that all the state required by this signal is calculated somewhere else and attached to the signal as a private struct object, or to some object reachable from it. Don’t worry about filtering for the “same train” cases, this is automatically done.&lt;br /&gt;
&lt;br /&gt;
If no reservation is desired, use the &amp;lt;code&amp;gt;empty&amp;lt;/code&amp;gt; global method available in all &amp;lt;code&amp;gt;ID&amp;amp;lt;Class&amp;amp;gt;&amp;lt;/code&amp;gt; types: &amp;lt;code&amp;gt;return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {}&lt;br /&gt;
struct Owner {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; {&lt;br /&gt;
    // some other, more full featured script function has attached Owner to this signal,&lt;br /&gt;
    // or not, so we need to check first&lt;br /&gt;
    if let owner &amp;amp;amp;= db.view&amp;amp;lt;Owner&amp;amp;gt;(signal) {&lt;br /&gt;
        if is_valid(db.view(owner.train_id)) {&lt;br /&gt;
            return owner.train_id;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_texture_state&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_texture_state ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_texture_state(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): i64 { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment, when the game UI needs to query what is the current signal texture state index, it will call your &amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt;, with some potential caching to keep the call rate lower. In any case the call rate of this function is potentially very large when the user zooms out the map, so make sure to keep its code as efficient as possible. For this same reason it is given very little access to the APIs.&lt;br /&gt;
&lt;br /&gt;
The return value indicates which signal texture state is to be used. If it’s -1 or lower, the default algorithm will be used to select the texture index. If it’s 0 or larger, it will select the texture in the same order as the &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; lines in the &amp;lt;code&amp;gt;SignalTextures&amp;lt;/code&amp;gt;. Larger values than the number of states will be clamped to the last state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_setup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_setup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_setup(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ss: &amp;amp;amp;mut ShiftSetup&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when an unassigned train decides to lookup a new shift to run, it will first call &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The parameter &amp;lt;code&amp;gt;ss&amp;lt;/code&amp;gt; is both an input and output parameter. It is initialized with the current, relevant data for the given train state, and &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; can then change it, to influence which shifts will be considered by the shift selection algorithm. It can change the train position used for matching, the time used for matching, and disable the check for reservations. For matched shifts which do not correspond to the current train position, the Extrapolator system will automatically pathfind a temporary milestone for the train, like other path-changing features.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_allow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_allow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_allow(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    run: &amp;amp;amp;Run,&lt;br /&gt;
    stop_idx: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    pose: &amp;amp;amp;Pose&lt;br /&gt;
): ShiftAllow { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when the shift selection algorithm fins a valid shift for the given train, it will call &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; with all the relevant data. The return of the function can then allow or deny the shift. If the shift is denied, the algorithm will resume immediately, trying other shifts&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are independent from each other, and can be used in any combination.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;linestop-event_line_stop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Line::Stop event_line_stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestStop extend Line::Stop {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestStop::event_line_stop(&lt;br /&gt;
    self: &amp;amp;amp;TestStop,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    stop: &amp;amp;amp;Line::Stop,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: LineStopEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == LineStopEvent::Arrive {&lt;br /&gt;
        log(&amp;amp;quot;@ arrives @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ departs @ @&amp;amp;quot;, train, line, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Line::Stop&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given line stop in the line editor. From that moment, when any train arrives or departs said line stop, &amp;lt;code&amp;gt;event_line_stop&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LineStopEvent::Depart&amp;lt;/code&amp;gt; to distinguish between arrival and departure. Waypoints are only called for &amp;lt;code&amp;gt;LineStopEvent::Arrive&amp;lt;/code&amp;gt;. Shift-less trains are also called.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;shift-event_shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Shift event_shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct TestShift extend Shift {&lt;br /&gt;
    a: i64,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
pub fn TestShift::event_shift(&lt;br /&gt;
    self: &amp;amp;amp;TestShift,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ev: ShiftEvent,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    if ev == ShiftEvent::Assign {&lt;br /&gt;
        log(&amp;amp;quot;@ assigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
        log(&amp;amp;quot;@ unassigned @ @&amp;amp;quot;, train, sched, self.a);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Shift&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given schedule shift in the line editor. From that moment, when any train is assigned to the shift, or becomes unassigned from the shift, &amp;lt;code&amp;gt;event_shift&amp;lt;/code&amp;gt; will be called. Use the &amp;lt;code&amp;gt;ev&amp;lt;/code&amp;gt; parameter &amp;lt;code&amp;gt;ShiftEvent::Assign&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ShiftEvent::Unassign&amp;lt;/code&amp;gt; to distinguish between assignation and unassignation. The &amp;lt;code&amp;gt;Assign&amp;lt;/code&amp;gt; event is called just after &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been set up, so it already has all the shift and run information. The &amp;lt;code&amp;gt;Unassign&amp;lt;/code&amp;gt; event is called just before &amp;lt;code&amp;gt;Motion&amp;lt;/code&amp;gt; has been cleared of all shift and run information so the script has access to as much information as possible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;controllers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Controllers ==&lt;br /&gt;
&lt;br /&gt;
Controller functions are called at a low frame rate compared to the overall simulation, with an (unchangeable) rate of once in 6 sim-seconds. In exchange they can invoke powerful ''commands'' as their execution result, and do not need any specific event or trigger to run, other than their enforced timer&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-control_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train control_train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct HateDepots extend Train {}&lt;br /&gt;
pub fn HateDepots::control_train(&lt;br /&gt;
    self: &amp;amp;amp;HateDepots,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    // train is already removed from the tracks, don't interfere with potential attempts at shift assignation&lt;br /&gt;
    if !is_valid(motion.presence.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is running a schedule, don't interfere&lt;br /&gt;
    if is_valid(motion.schedule_dispatch.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is present, but it is not running a schedule, so despawn it&lt;br /&gt;
    sc.queue_train_intervention(train);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The train motion engine will call train controllers after the entire simulation for a given frame is done, and all threads are finished. Command execution will only happen after all train controllers for a given frame are done. In other words, train controllers are given a consistent, read-only snapshot of the train sim, and queue up work to be executed by the sim. They never directly change the sim in any way, allowing train controller execution to be fully parallel.&lt;br /&gt;
&lt;br /&gt;
After all controllers are run, and all their non-task commands are executed, tasks are executed. Read more about tasks later on. Any tasks with a deadline which expired in this frame a run at this time too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontroller-command-queue&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== SimController command queue ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; object implements an API to control the simulation, including modification of some parameters and behaviors. It is also responsible for attaching and erasing private struct data from game objects, on behalf of scripts. The execution of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; is based on a command queue. Every call queues a command and returns immediately to the script code, without making any changes to the game state. Therefore the game state never changes while the script code is running.&lt;br /&gt;
&lt;br /&gt;
For control scripts, commands are executed asynchronously, there is no guaranteed order of execution! You must prepare your code and data for this design. For tasks scripts commands are executed in order and in isolation. You can queue up tasks from control scripts when you need to guarantee data consistency beyond “pick a random winner”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_intervention&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_intervention ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks, releases its schedule shift (if any), and deletes and refunds its pax (if any). No other cost other than pax refunds is issued. This function can be used as a general “despawn the train” feature, not just for exceptional circumstances.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_warp&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_warp ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks and repositions it at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, re-pathing it to its currently scheduled destination (if any), and setting its speed to 0. This is basically a train wormhole. The train keeps its shift and pax, if any.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_drive_to&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_drive_to ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Re-paths the train path to end at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, without any changes to its shift or pax (if any). It is possible for any future &amp;lt;code&amp;gt;queue_train_drive_to&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; to reset this path at any point, losing the destination. “Queue” here is used as part of the SimController API semantics, it does not mean the train keeps a queue of positions to reach. If the path is not interrupted and the train reaches &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; it will re-path itself towards its current scheduled stop, if it has any, or brake to a stop if unassigned. If &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; was also in the stop area set for its current scheduled stop it will also brake to stop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_attach&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_attach ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the attachment of the &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) to the &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt;, which must be of one of the following types: &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attached objects can be accessed with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt; at some point in the future. If called from a controller function, the attached object will be accessible after all controller functions are done for a given frame. If called from a task, he attached object will be accessible immediately after the task returns, and before any other task is executed. In other words, tasks are transaction-like, in the sense they view an immutable snapshot of the game state, and any changes they queue are executed before any other task, and then visible from these other tasks.&lt;br /&gt;
&lt;br /&gt;
Attaching an object of a given private struct type when it already exists attached to a &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt; will overwrite it. This is how private data is updated from scripting: by using &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; to copy any existing data, modifying the copy, then calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; to replace the existing data. Therefore it is a good idea to keep your private structs small. Only one instance of a given private struct type can be attached to any particular model object, but you can attach as many different private struct types as you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_erase&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_erase ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the erasure of &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt;, which must obtained using with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt;. Trying to erase temporary objects (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) is ignored. The execution of the queued erase commands is analog to the &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; case. In particular a sequences of attach and erase queued from controllers will produce undefined results (impossible to predict which attach and/or erase wins). For example multiple attach from a controller for the same model_obj and private struct type will implicitly pick a singular “winner” attach, but the script does not have any control over which one. Sequences of attach and erase queued from tasks are strictly ordered and isolated, so they produce consistent results, in the same order they were queued in the task script, without any concurrent changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task-and-simcontrollerqueue_task_at&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task and SimController::queue_task_at ===&lt;br /&gt;
&lt;br /&gt;
These functions are documented in the next section.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
Tasks are a very special kind of command which allows scripts to dynamically queue “future work”. Scripts with access to &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; can call this function to queue up a task for future script execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; must be of a private struct type which implements &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example { ... }&lt;br /&gt;
pub fn Example::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
For example, a train controller script could decide it needs to delay some decision into a task for data consistency reasons (other controllers are running at the same time), and delegate into a task rather than directly calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ControlTrain extend Train { ... }&lt;br /&gt;
pub fn ControlTrain::control_train(&lt;br /&gt;
    self: &amp;amp;amp;ControlTrain,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    task.train_id = train.id;&lt;br /&gt;
    task.v = some_data_from_somewhere;&lt;br /&gt;
    task.prio = 42; // or something smarter, like from ControlTrain, other objects, etc.&lt;br /&gt;
    sc.queue_task(task);&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
struct Task {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
struct SomeData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
pub fn Task::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    let train &amp;amp;amp;= ctx.db.view(self.train_id) else { return; }&lt;br /&gt;
    if let existing &amp;amp;amp;= ctx.db.view&amp;amp;lt;SomeData&amp;amp;gt;(train) {&lt;br /&gt;
        if existing.prio &amp;amp;gt;= self.prio {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    let data = SomeData::new();&lt;br /&gt;
    data.v = self.v;&lt;br /&gt;
    data.prio = self.prio;&lt;br /&gt;
    sc.queue_attach(train, data);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the previous example, maybe &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; will be called multiple times because multiple &amp;lt;code&amp;gt;ControlTrain::control_train()&amp;lt;/code&amp;gt; instances queued objects of &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;, but each execution will be single threaded, and all its queued &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; commands will be executed just after the call is done and before any other &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; call (for &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; or any other struct type), therefore the algorithm to pick a winner based on an explicit priority works.&lt;br /&gt;
&lt;br /&gt;
As mentioned, task execution is single threaded. The game does not feature a real concurrent database, instead all concurrent access is bespoke and very carefully designed to avoid deadlocks and inconsistencies (this is much faster than a general purpose concurrent database). Scripts also run in this parallel system, but their access to the game state is carefully restricted as explained earlier. But in the end, scripts also need to modify data, and do so in a consistent way. Tasks solve this issue, but do so in the most pessimistic possible way, by being single threaded. Therefore script developers should use them in moderation. Consider the “random winner” semantics of control script queuing first, which are completely free performance wise, before deciding you need a task. It is often the case a concurrent problem reduces to “pick 0 or 1 winners, any winner, but never 2 or more” and the default queue semantics already provide that guarantee for attaching a specific model/private pair.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; is provided with &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt;, therefore it can queue tasks itself. But unlike controller queuing tasks, which are guaranteed to run on the same frame, tasks queued from tasks are guaranteed to ''not'' run on the same frame, on purpose. They are deliberately stored away and forced a delay of 6 sim-seconds. This is to avoid misuse of tasks, and infinite looping.&lt;br /&gt;
&lt;br /&gt;
This behavior might even be desirable in certain scripts, for example if you are developing some stateful signal system and you need some kind of “cleanup” task that makes sure some signal being owned by some train is still the focus of said train. You can deliberately queue tasks for future simulation frames with &amp;lt;code&amp;gt;queue_task_at&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;deadline&amp;lt;/code&amp;gt; is expressed as microseconds since the start of the current save world. You can obtain the current simulation frame &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; value with &amp;lt;code&amp;gt;Extrapolator::clock_us()&amp;lt;/code&amp;gt;, like in this example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;    // schedule task to run 10 sim-s from now&lt;br /&gt;
    sc.queue_task_at(task, ctx.extrapolator.clock_us() + 10000000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-controlctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ControlCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ControlCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    sim: &amp;amp;amp;Sim,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim controller scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects, and associated script stuct objects.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::track_pos_project(self: &amp;amp;amp;DB, pos: &amp;amp;amp;Pos, distance: f64): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return a track position separated by ‘distance’ meters from ‘pos’, in the direction of ‘pos’. If distance is negative it will be in the opposite direction. Can only follow the main track. Merges and dead ends will return a Pos a shorter distance away. Signals are ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB): &amp;amp;amp;Script&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-eventctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type EventCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct EventCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim event handler scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line::Stop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line::Stop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    station_stop: std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;,&lt;br /&gt;
    run_stop: std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
    run_dispatch: std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;,&lt;br /&gt;
    hitch: std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionhitch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Hitch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Hitch {&lt;br /&gt;
    driver_train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Train is being hitched by a driver train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionrundispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::RunDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::RunDispatch {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionstationstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::StationStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::StationStop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Schedule::view(self: &amp;amp;amp;Schedule, shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;): *Shift&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns a pointer to the shift, if it’s contained in this schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-script&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Script ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Script {&lt;br /&gt;
    id: ID&amp;amp;lt;Script&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Shift {&lt;br /&gt;
    id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::kind(self: &amp;amp;amp;Signal): mut SignalKind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the signal kind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Hitch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;): *Motion::Hitch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStationEvent&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;&lt;br /&gt;
): *Motion::StationStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Script&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Shift&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Shift&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Shift&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::clock_us(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current microseconds since the creation of this saved game. This is used as the timing root of the simulation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second since 1970-01-01:00:00:00.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_occupation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_reservation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying or reserving the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_occupying(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_reserving(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying or reserving the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
Probe a track position for train reservations and occupations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Seconds since 1970-01-01:00:00:00 for Monday 00:00:00 of the current week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-linestopevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type LineStopEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum LineStopEvent {&lt;br /&gt;
    Arrive,&lt;br /&gt;
    Depart,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
Advance the iterator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftallow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftAllow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftAllow {&lt;br /&gt;
    Allow,&lt;br /&gt;
    Deny,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftEvent {&lt;br /&gt;
    Assign,&lt;br /&gt;
    Unassign,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftsetup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftSetup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ShiftSetup {&lt;br /&gt;
    skip: bool,&lt;br /&gt;
    match_pos: bool,&lt;br /&gt;
    check_occupation: bool,&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores the context of a train shift lookup.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function wants to change the train path, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signallookaheadresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalLookaheadResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalLookaheadResult {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores extra information associated with the result of the signal lookahead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-sim&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Sim ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Sim {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of the simulation state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Sim::view&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Sim, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A proxy mutable API to the simulation engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_hitch(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    driver: &amp;amp;amp;Train,&lt;br /&gt;
    hitcher: &amp;amp;amp;Train&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(self: &amp;amp;amp;mut SimController, train: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_run_line(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    arrival_offset_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_configuration(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    config: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_unhitch(self: &amp;amp;amp;mut SimController, hitcher: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=550</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=550"/>
		<updated>2025-12-18T10:46:38Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used in game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration, integer division or arbitrary setting of pointers and references, and most data exposed to scripts is read-only, strictly enforced by the language. Any expression result which could result in an out of bounds or invalid memory access must be checked for validity, and the API design together with the type system enforces it.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
pub struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;SpeedTrap,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- VisMod? 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' NAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Script&amp;lt;/code&amp;gt; (with restrictions)&lt;br /&gt;
&lt;br /&gt;
Structs extending game types for player extensions must be declared as &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt;. When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
To read struct objects from script code they must be looked up using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API. Therefore only functions provided with &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt; object (or a context object with contains &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt;) can look up these objects. But you can pass around &amp;lt;code&amp;gt;DB&amp;amp;amp;&amp;lt;/code&amp;gt; as a parameter without any lifetime restrictions, since it’s a purely read only API. This API also works for non-pub structs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= ctx.db.view&amp;amp;lt;Example&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    log(&amp;amp;quot;v = @&amp;amp;quot;, config.v);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;pub-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== pub structs ====&lt;br /&gt;
&lt;br /&gt;
As explained earlier, &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs are the user interface of your scripts. They are exposed in the UI as input forms, and their &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;s can give some control over this rendering. Conceptually they are owned by the player of the game as part of the game object database, by attaching them to a game model object in the database, not the script. Scripts do not have any capability to create, edit or delete objects of &amp;lt;code&amp;gt;pub struct&amp;lt;/code&amp;gt;s. It is always the player who decides when to create a new object of these structs by interacting in the UI. Scripts can then read, and only read, the content of these objects, by using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API presented earlier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs have a very powerful capability: they have limited support for forward schema evolution. This means that the script developer can add to, and reorder, fields in &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, and the game runtime will be able keep the contents of the other fields intact. This is very important to respect the input data by the player. If you rename &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs or their fields, or change their types, the player input data will be lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;non-pub-or-private-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Non-pub (or private) structs ====&lt;br /&gt;
&lt;br /&gt;
Non-&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, also called private structs, are conceptually owned by the script as a part of the simulation, not the player. Their contents are assumed to be a black box by the rest of the game. Scripts are allowed to create and modify objects of these structs during their execution, which are automatically deleted at the end of the simulation frame. It is also possible to attach these structs to existing game model objects to extend their lifetime beyond the current frame. In this case their lifetime becomes the same as the game object, and they can be retrieved in later frames for reading, deleted or overwritten as desired.&lt;br /&gt;
&lt;br /&gt;
Private structs ''do not support schema evolution''. Changing field types, field names, reordering of fields, even just adding new fields at the end, will always result in losing all existing attached objects of the given struct. Some operations like resetting the simulation will also erase attached objects, because they are considered simulation state, not player created objects.&lt;br /&gt;
&lt;br /&gt;
Private structs support dynamic memory allocation. All private struct definitions automatically create a &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; method for the struct:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct PrivData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let ro &amp;amp;amp;= ctx.db.view&amp;amp;lt;PrivData&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    let rw &amp;amp;amp;mut= PrivData::clone(ro);&lt;br /&gt;
    rw.v = 100;&lt;br /&gt;
    let empty &amp;amp;amp;mut= PrivData::new();&lt;br /&gt;
    empty.v = 200;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The objects allocated by &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; are always deleted at the end of the current simulation frame. Their lifetime can be extended beyond the current frame by attaching them to a game object, like &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, so their lifetime becomes the same as the attached object. The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API has methods for attaching and erasing these object.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;host-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Host structs ====&lt;br /&gt;
&lt;br /&gt;
Many of the exposed game APIs are also based around structs. These structs do not follow any of the previous rules. Some have special capabilities, for example simple structs like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt; are ''value objects'': they can be copied and passed around like any &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; would. Some others are strictly locked down and serve as very little beyond a way to keep a pointer safe. In general, when working with game API structs, assume they are what would be called ''move only'' in C++. And NimbyScript has no move operator or semantics, so in essence assume they are immutable, immobile references, except when documented otherwise (like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As an aside, all script declared &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; or not) are also always ''move only'', and always “owned” by some external entity. This is why the APIs for their manipulation are always based on pointers and references, even for private structs. It is not possible to create plain, stack allocated values of script structs, or to use them as fields in structs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version:&lt;br /&gt;
&lt;br /&gt;
* Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
* Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums)&lt;br /&gt;
* For pub structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* For private structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In pub structs these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types. &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; will also display a small list editor. Keep in mind the correct type is &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;Vec&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- 'let' BindBody 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- 'let' BindBody ';'&lt;br /&gt;
BindBody    &amp;amp;lt;- NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' 'let' BindBody BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- ColonNAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere pointer types cannot be dereferenced, therefore cannot be used in dot expressions. The exception is the built-in function &amp;lt;code&amp;gt;is_valid(ptr): bool&amp;lt;/code&amp;gt;, which is usable with any pointer type.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;extensions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Extensions =&lt;br /&gt;
&lt;br /&gt;
Extending game database struct data with &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt; can also be used to extend the game code. The mechanism to do so is to first declare a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;ing a game database object (with or without fields). Then create a specifically named and parametrized function which will be called by the game under certain situations, for certain kinds of objects.&lt;br /&gt;
&lt;br /&gt;
All extension functions take a &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter which is a reference to the struct which it is method of, called &amp;lt;code&amp;gt;Example&amp;lt;/code&amp;gt; in the following sections. Replace it with your struct name. The rest of the parameters are fixed and must be reproduced exactly as-is.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
Event functions are called as part of the core simulation engine. They are meant to be focused in features and quick to execute. These functions might be called thousands of times per simulation frame, including multiple redundant times. Their capability to change the simulation behavior is usually very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_check&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_check ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails, or if another script call returns &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_lookahead&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_lookahead ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_lookahead(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    train_distance: f64,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalLookaheadResult&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; function at regular intervals for each signal 15km ahead of the train path. It is called for all signals, until one of these conditions hold: - One of the signals path checks as &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; - Another train is found - The train stop is found - 15km have been checked&lt;br /&gt;
&lt;br /&gt;
For both &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; signals, your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; will be called, and you can check the path find result in &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;, and the distance from the train in &amp;lt;code&amp;gt;train_distance&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; allows to set a maximum speed for the train, which goes into effect immediately. This works from any distance and past any amount of signals between the train and the caller signal. If multiple signals in the lookahead path return a &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt;, the slowest speed is picked. If no &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt; is set, or it is 0, the result is ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; default value is 0, which is considered invalid and will be ignored. To stop the train at the signal implement &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_change_path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_change_path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_change_path(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The current path check result of this signal for the passed train is passed as &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;. This already includes any results from &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_pass_by&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_pass_by ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_pass_by(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; function on the exact simulation frame a train passes by the exact point of the signal on the track.&lt;br /&gt;
&lt;br /&gt;
This function has no return result. Instead, since it has a predictably low call rate compared to the other events, it is the only event function with access to the powerful &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_marker_reserved&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_marker_reserved ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given marker signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; any time the reservation check algorithm is tracing a path which goes over the marker signal, on any direction, giving it the chance to report an arbitrary train as the reserver of that point on the track.&lt;br /&gt;
&lt;br /&gt;
This signal has a potential huge call rate, and for this reason it is given very little access to the APIs. The intention is that all the state required by this signal is calculated somewhere else and attached to the signal as a private struct object, or to some object reachable from it. Don’t worry about filtering for the “same train” cases, this is automatically done.&lt;br /&gt;
&lt;br /&gt;
If no reservation is desired, use the &amp;lt;code&amp;gt;empty&amp;lt;/code&amp;gt; global method available in all &amp;lt;code&amp;gt;ID&amp;amp;lt;Class&amp;amp;gt;&amp;lt;/code&amp;gt; types: &amp;lt;code&amp;gt;return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {}&lt;br /&gt;
struct Owner {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; {&lt;br /&gt;
    // some other, more full featured script function has attached Owner to this signal,&lt;br /&gt;
    // or not, so we need to check first&lt;br /&gt;
    if let owner &amp;amp;amp;= db.view&amp;amp;lt;Owner&amp;amp;gt;(signal) {&lt;br /&gt;
        if is_valid(db.view(owner.train_id)) {&lt;br /&gt;
            return owner.train_id;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_texture_state&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_texture_state ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_texture_state(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): i64 { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment, when the game UI needs to query what is the current signal texture state index, it will call your &amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt;, with some potential caching to keep the call rate lower. In any case the call rate of this function is potentially very large when the user zooms out the map, so make sure to keep its code as efficient as possible. For this same reason it is given very little access to the APIs.&lt;br /&gt;
&lt;br /&gt;
The return value indicates which signal texture state is to be used. If it’s -1 or lower, the default algorithm will be used to select the texture index. If it’s 0 or larger, it will select the texture in the same order as the &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; lines in the &amp;lt;code&amp;gt;SignalTextures&amp;lt;/code&amp;gt;. Larger values than the number of states will be clamped to the last state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_setup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_setup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_setup(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ss: &amp;amp;amp;mut ShiftSetup&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when an unassigned train decides to lookup a new shift to run, it will first call &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The parameter &amp;lt;code&amp;gt;ss&amp;lt;/code&amp;gt; is both an input and output parameter. It is initialized with the current, relevant data for the given train state, and &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; can then change it, to influence which shifts will be considered by the shift selection algorithm. It can change the train position used for matching, the time used for matching, and disable the check for reservations. For matched shifts which do not correspond to the current train position, the Extrapolator system will automatically pathfind a temporary milestone for the train, like other path-changing features.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_allow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_allow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_allow(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    run: &amp;amp;amp;Run,&lt;br /&gt;
    stop_idx: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    pose: &amp;amp;amp;Pose&lt;br /&gt;
): ShiftAllow { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when the shift selection algorithm fins a valid shift for the given train, it will call &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; with all the relevant data. The return of the function can then allow or deny the shift. If the shift is denied, the algorithm will resume immediately, trying other shifts&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are independent from each other, and can be used in any combination.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;controllers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Controllers ==&lt;br /&gt;
&lt;br /&gt;
Controller functions are called at a low frame rate compared to the overall simulation, with an (unchangeable) rate of once in 6 sim-seconds. In exchange they can invoke powerful ''commands'' as their execution result, and do not need any specific event or trigger to run, other than their enforced timer&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-control_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train control_train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct HateDepots extend Train {}&lt;br /&gt;
pub fn HateDepots::control_train(&lt;br /&gt;
    self: &amp;amp;amp;HateDepots,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    // train is already removed from the tracks, don't interfere with potential attempts at shift assignation&lt;br /&gt;
    if !is_valid(motion.presence.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is running a schedule, don't interfere&lt;br /&gt;
    if is_valid(motion.schedule_dispatch.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is present, but it is not running a schedule, so despawn it&lt;br /&gt;
    sc.queue_train_intervention(train);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The train motion engine will call train controllers after the entire simulation for a given frame is done, and all threads are finished. Command execution will only happen after all train controllers for a given frame are done. In other words, train controllers are given a consistent, read-only snapshot of the train sim, and queue up work to be executed by the sim. They never directly change the sim in any way, allowing train controller execution to be fully parallel.&lt;br /&gt;
&lt;br /&gt;
After all controllers are run, and all their non-task commands are executed, tasks are executed. Read more about tasks later on. Any tasks with a deadline which expired in this frame a run at this time too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontroller-command-queue&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== SimController command queue ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; object implements an API to control the simulation, including modification of some parameters and behaviors. It is also responsible for attaching and erasing private struct data from game objects, on behalf of scripts. The execution of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; is based on a command queue. Every call queues a command and returns immediately to the script code, without making any changes to the game state. Therefore the game state never changes while the script code is running.&lt;br /&gt;
&lt;br /&gt;
For control scripts, commands are executed asynchronously, there is no guaranteed order of execution! You must prepare your code and data for this design. For tasks scripts commands are executed in order and in isolation. You can queue up tasks from control scripts when you need to guarantee data consistency beyond “pick a random winner”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_intervention&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_intervention ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks, releases its schedule shift (if any), and deletes and refunds its pax (if any). No other cost other than pax refunds is issued. This function can be used as a general “despawn the train” feature, not just for exceptional circumstances.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_warp&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_warp ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks and repositions it at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, re-pathing it to its currently scheduled destination (if any), and setting its speed to 0. This is basically a train wormhole. The train keeps its shift and pax, if any.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_drive_to&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_drive_to ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Re-paths the train path to end at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, without any changes to its shift or pax (if any). It is possible for any future &amp;lt;code&amp;gt;queue_train_drive_to&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; to reset this path at any point, losing the destination. “Queue” here is used as part of the SimController API semantics, it does not mean the train keeps a queue of positions to reach. If the path is not interrupted and the train reaches &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; it will re-path itself towards its current scheduled stop, if it has any, or brake to a stop if unassigned. If &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; was also in the stop area set for its current scheduled stop it will also brake to stop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_attach&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_attach ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the attachment of the &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) to the &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt;, which must be of one of the following types: &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attached objects can be accessed with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt; at some point in the future. If called from a controller function, the attached object will be accessible after all controller functions are done for a given frame. If called from a task, he attached object will be accessible immediately after the task returns, and before any other task is executed. In other words, tasks are transaction-like, in the sense they view an immutable snapshot of the game state, and any changes they queue are executed before any other task, and then visible from these other tasks.&lt;br /&gt;
&lt;br /&gt;
Attaching an object of a given private struct type when it already exists attached to a &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt; will overwrite it. This is how private data is updated from scripting: by using &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; to copy any existing data, modifying the copy, then calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; to replace the existing data. Therefore it is a good idea to keep your private structs small. Only one instance of a given private struct type can be attached to any particular model object, but you can attach as many different private struct types as you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_erase&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_erase ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the erasure of &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt;, which must obtained using with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt;. Trying to erase temporary objects (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) is ignored. The execution of the queued erase commands is analog to the &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; case. In particular a sequences of attach and erase queued from controllers will produce undefined results (impossible to predict which attach and/or erase wins). For example multiple attach from a controller for the same model_obj and private struct type will implicitly pick a singular “winner” attach, but the script does not have any control over which one. Sequences of attach and erase queued from tasks are strictly ordered and isolated, so they produce consistent results, in the same order they were queued in the task script, without any concurrent changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task-and-simcontrollerqueue_task_at&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task and SimController::queue_task_at ===&lt;br /&gt;
&lt;br /&gt;
These functions are documented in the next section.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
Tasks are a very special kind of command which allows scripts to dynamically queue “future work”. Scripts with access to &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; can call this function to queue up a task for future script execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; must be of a private struct type which implements &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example { ... }&lt;br /&gt;
pub fn Example::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
For example, a train controller script could decide it needs to delay some decision into a task for data consistency reasons (other controllers are running at the same time), and delegate into a task rather than directly calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ControlTrain extend Train { ... }&lt;br /&gt;
pub fn ControlTrain::control_train(&lt;br /&gt;
    self: &amp;amp;amp;ControlTrain,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    task.train_id = train.id;&lt;br /&gt;
    task.v = some_data_from_somewhere;&lt;br /&gt;
    task.prio = 42; // or something smarter, like from ControlTrain, other objects, etc.&lt;br /&gt;
    sc.queue_task(task);&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
struct Task {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
struct SomeData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
pub fn Task::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    let train &amp;amp;amp;= ctx.db.view(self.train_id) else { return; }&lt;br /&gt;
    if let existing &amp;amp;amp;= ctx.db.view&amp;amp;lt;SomeData&amp;amp;gt;(train) {&lt;br /&gt;
        if existing.prio &amp;amp;gt;= self.prio {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    let data = SomeData::new();&lt;br /&gt;
    data.v = self.v;&lt;br /&gt;
    data.prio = self.prio;&lt;br /&gt;
    sc.queue_attach(train, data);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the previous example, maybe &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; will be called multiple times because multiple &amp;lt;code&amp;gt;ControlTrain::control_train()&amp;lt;/code&amp;gt; instances queued objects of &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;, but each execution will be single threaded, and all its queued &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; commands will be executed just after the call is done and before any other &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; call (for &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; or any other struct type), therefore the algorithm to pick a winner based on an explicit priority works.&lt;br /&gt;
&lt;br /&gt;
As mentioned, task execution is single threaded. The game does not feature a real concurrent database, instead all concurrent access is bespoke and very carefully designed to avoid deadlocks and inconsistencies (this is much faster than a general purpose concurrent database). Scripts also run in this parallel system, but their access to the game state is carefully restricted as explained earlier. But in the end, scripts also need to modify data, and do so in a consistent way. Tasks solve this issue, but do so in the most pessimistic possible way, by being single threaded. Therefore script developers should use them in moderation. Consider the “random winner” semantics of control script queuing first, which are completely free performance wise, before deciding you need a task. It is often the case a concurrent problem reduces to “pick 0 or 1 winners, any winner, but never 2 or more” and the default queue semantics already provide that guarantee for attaching a specific model/private pair.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; is provided with &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt;, therefore it can queue tasks itself. But unlike controller queuing tasks, which are guaranteed to run on the same frame, tasks queued from tasks are guaranteed to ''not'' run on the same frame, on purpose. They are deliberately stored away and forced a delay of 6 sim-seconds. This is to avoid misuse of tasks, and infinite looping.&lt;br /&gt;
&lt;br /&gt;
This behavior might even be desirable in certain scripts, for example if you are developing some stateful signal system and you need some kind of “cleanup” task that makes sure some signal being owned by some train is still the focus of said train. You can deliberately queue tasks for future simulation frames with &amp;lt;code&amp;gt;queue_task_at&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;deadline&amp;lt;/code&amp;gt; is expressed as microseconds since the start of the current save world. You can obtain the current simulation frame &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; value with &amp;lt;code&amp;gt;Extrapolator::clock_us()&amp;lt;/code&amp;gt;, like in this example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;    // schedule task to run 10 sim-s from now&lt;br /&gt;
    sc.queue_task_at(task, ctx.extrapolator.clock_us() + 10000000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-controlctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ControlCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ControlCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    sim: &amp;amp;amp;Sim,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim controller scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects, and associated script stuct objects.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::track_pos_project(self: &amp;amp;amp;DB, pos: &amp;amp;amp;Pos, distance: f64): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return a track position separated by ‘distance’ meters from ‘pos’, in the direction of ‘pos’. If distance is negative it will be in the opposite direction. Can only follow the main track. Merges and dead ends will return a Pos a shorter distance away. Signals are ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB): &amp;amp;amp;Script&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-eventctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type EventCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct EventCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim event handler scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    station_stop: std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;,&lt;br /&gt;
    run_stop: std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
    run_dispatch: std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;,&lt;br /&gt;
    hitch: std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionhitch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Hitch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Hitch {&lt;br /&gt;
    driver_train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Train is being hitched by a driver train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionrundispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::RunDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::RunDispatch {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionstationstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::StationStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::StationStop {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Schedule::view(self: &amp;amp;amp;Schedule, shift_id: ID&amp;amp;lt;Shift&amp;amp;gt;): *Shift&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns a pointer to the shift, if it’s contained in this schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-script&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Script ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Script {&lt;br /&gt;
    id: ID&amp;amp;lt;Script&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Shift {&lt;br /&gt;
    id: ID&amp;amp;lt;Shift&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::kind(self: &amp;amp;amp;Signal): mut SignalKind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the signal kind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Hitch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;): *Motion::Hitch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::RunStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::RunStop&amp;amp;gt;): *Motion::RunDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStationEvent&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::StationStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;&lt;br /&gt;
): *Motion::StationStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Script&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Shift&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Shift&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Shift&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Shift&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Shift&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::clock_us(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current microseconds since the creation of this saved game. This is used as the timing root of the simulation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second since 1970-01-01:00:00:00.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_occupation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_reservation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying or reserving the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_occupying(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_reserving(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying or reserving the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
Probe a track position for train reservations and occupations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Seconds since 1970-01-01:00:00:00 for Monday 00:00:00 of the current week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
Advance the iterator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftallow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftAllow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftAllow {&lt;br /&gt;
    Allow,&lt;br /&gt;
    Deny,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftsetup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftSetup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ShiftSetup {&lt;br /&gt;
    skip: bool,&lt;br /&gt;
    match_pos: bool,&lt;br /&gt;
    check_occupation: bool,&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores the context of a train shift lookup.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function wants to change the train path, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signallookaheadresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalLookaheadResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalLookaheadResult {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores extra information associated with the result of the signal lookahead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-sim&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Sim ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Sim {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of the simulation state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Sim::view&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Sim, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A proxy mutable API to the simulation engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_hitch(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    driver: &amp;amp;amp;Train,&lt;br /&gt;
    hitcher: &amp;amp;amp;Train&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(self: &amp;amp;amp;mut SimController, train: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_run_line(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    line: &amp;amp;amp;Line,&lt;br /&gt;
    arrival_offset_s: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_configuration(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    config: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_unhitch(self: &amp;amp;amp;mut SimController, hitcher: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=549</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=549"/>
		<updated>2025-12-12T13:15:47Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used in game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration, integer division or arbitrary setting of pointers and references, and most data exposed to scripts is read-only, strictly enforced by the language. Any expression result which could result in an out of bounds or invalid memory access must be checked for validity, and the API design together with the type system enforces it.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
pub struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;SpeedTrap,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- VisMod? 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' NAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Script&amp;lt;/code&amp;gt; (with restrictions)&lt;br /&gt;
&lt;br /&gt;
Structs extending game types for player extensions must be declared as &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt;. When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
To read struct objects from script code they must be looked up using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API. Therefore only functions provided with &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt; object (or a context object with contains &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt;) can look up these objects. But you can pass around &amp;lt;code&amp;gt;DB&amp;amp;amp;&amp;lt;/code&amp;gt; as a parameter without any lifetime restrictions, since it’s a purely read only API. This API also works for non-pub structs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= ctx.db.view&amp;amp;lt;Example&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    log(&amp;amp;quot;v = @&amp;amp;quot;, config.v);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;pub-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== pub structs ====&lt;br /&gt;
&lt;br /&gt;
As explained earlier, &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs are the user interface of your scripts. They are exposed in the UI as input forms, and their &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;s can give some control over this rendering. Conceptually they are owned by the player of the game as part of the game object database, by attaching them to a game model object in the database, not the script. Scripts do not have any capability to create, edit or delete objects of &amp;lt;code&amp;gt;pub struct&amp;lt;/code&amp;gt;s. It is always the player who decides when to create a new object of these structs by interacting in the UI. Scripts can then read, and only read, the content of these objects, by using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API presented earlier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs have a very powerful capability: they have limited support for forward schema evolution. This means that the script developer can add to, and reorder, fields in &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, and the game runtime will be able keep the contents of the other fields intact. This is very important to respect the input data by the player. If you rename &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs or their fields, or change their types, the player input data will be lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;non-pub-or-private-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Non-pub (or private) structs ====&lt;br /&gt;
&lt;br /&gt;
Non-&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, also called private structs, are conceptually owned by the script as a part of the simulation, not the player. Their contents are assumed to be a black box by the rest of the game. Scripts are allowed to create and modify objects of these structs during their execution, which are automatically deleted at the end of the simulation frame. It is also possible to attach these structs to existing game model objects to extend their lifetime beyond the current frame. In this case their lifetime becomes the same as the game object, and they can be retrieved in later frames for reading, deleted or overwritten as desired.&lt;br /&gt;
&lt;br /&gt;
Private structs ''do not support schema evolution''. Changing field types, field names, reordering of fields, even just adding new fields at the end, will always result in losing all existing attached objects of the given struct. Some operations like resetting the simulation will also erase attached objects, because they are considered simulation state, not player created objects.&lt;br /&gt;
&lt;br /&gt;
Private structs support dynamic memory allocation. All private struct definitions automatically create a &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; method for the struct:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct PrivData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let ro &amp;amp;amp;= ctx.db.view&amp;amp;lt;PrivData&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    let rw &amp;amp;amp;mut= PrivData::clone(ro);&lt;br /&gt;
    rw.v = 100;&lt;br /&gt;
    let empty &amp;amp;amp;mut= PrivData::new();&lt;br /&gt;
    empty.v = 200;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The objects allocated by &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; are always deleted at the end of the current simulation frame. Their lifetime can be extended beyond the current frame by attaching them to a game object, like &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, so their lifetime becomes the same as the attached object. The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API has methods for attaching and erasing these object.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;host-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Host structs ====&lt;br /&gt;
&lt;br /&gt;
Many of the exposed game APIs are also based around structs. These structs do not follow any of the previous rules. Some have special capabilities, for example simple structs like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt; are ''value objects'': they can be copied and passed around like any &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; would. Some others are strictly locked down and serve as very little beyond a way to keep a pointer safe. In general, when working with game API structs, assume they are what would be called ''move only'' in C++. And NimbyScript has no move operator or semantics, so in essence assume they are immutable, immobile references, except when documented otherwise (like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As an aside, all script declared &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; or not) are also always ''move only'', and always “owned” by some external entity. This is why the APIs for their manipulation are always based on pointers and references, even for private structs. It is not possible to create plain, stack allocated values of script structs, or to use them as fields in structs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version:&lt;br /&gt;
&lt;br /&gt;
* Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
* Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums)&lt;br /&gt;
* For pub structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* For private structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In pub structs these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types. &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; will also display a small list editor. Keep in mind the correct type is &amp;lt;code&amp;gt;&amp;amp;amp;Vec&amp;lt;/code&amp;gt;, not &amp;lt;code&amp;gt;Vec&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- 'let' BindBody 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- 'let' BindBody ';'&lt;br /&gt;
BindBody    &amp;amp;lt;- NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' 'let' BindBody BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- ColonNAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere pointer types cannot be dereferenced, therefore cannot be used in dot expressions. The exception is the built-in function &amp;lt;code&amp;gt;is_valid(ptr): bool&amp;lt;/code&amp;gt;, which is usable with any pointer type.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;extensions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Extensions =&lt;br /&gt;
&lt;br /&gt;
Extending game database struct data with &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt; can also be used to extend the game code. The mechanism to do so is to first declare a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;ing a game database object (with or without fields). Then create a specifically named and parametrized function which will be called by the game under certain situations, for certain kinds of objects.&lt;br /&gt;
&lt;br /&gt;
All extension functions take a &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter which is a reference to the struct which it is method of, called &amp;lt;code&amp;gt;Example&amp;lt;/code&amp;gt; in the following sections. Replace it with your struct name. The rest of the parameters are fixed and must be reproduced exactly as-is.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
Event functions are called as part of the core simulation engine. They are meant to be focused in features and quick to execute. These functions might be called thousands of times per simulation frame, including multiple redundant times. Their capability to change the simulation behavior is usually very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_check&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_check ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails, or if another script call returns &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_lookahead&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_lookahead ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_lookahead(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    train_distance: f64,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalLookaheadResult&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; function at regular intervals for each signal 15km ahead of the train path. It is called for all signals, until one of these conditions hold: - One of the signals path checks as &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; - Another train is found - The train stop is found - 15km have been checked&lt;br /&gt;
&lt;br /&gt;
For both &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; signals, your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; will be called, and you can check the path find result in &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;, and the distance from the train in &amp;lt;code&amp;gt;train_distance&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; allows to set a maximum speed for the train, which goes into effect immediately. This works from any distance and past any amount of signals between the train and the caller signal. If multiple signals in the lookahead path return a &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt;, the slowest speed is picked. If no &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt; is set, or it is 0, the result is ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; default value is 0, which is considered invalid and will be ignored. To stop the train at the signal implement &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_change_path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_change_path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_change_path(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The current path check result of this signal for the passed train is passed as &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;. This already includes any results from &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_pass_by&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_pass_by ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_pass_by(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; function on the exact simulation frame a train passes by the exact point of the signal on the track.&lt;br /&gt;
&lt;br /&gt;
This function has no return result. Instead, since it has a predictably low call rate compared to the other events, it is the only event function with access to the powerful &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_marker_reserved&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_marker_reserved ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given marker signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; any time the reservation check algorithm is tracing a path which goes over the marker signal, on any direction, giving it the chance to report an arbitrary train as the reserver of that point on the track.&lt;br /&gt;
&lt;br /&gt;
This signal has a potential huge call rate, and for this reason it is given very little access to the APIs. The intention is that all the state required by this signal is calculated somewhere else and attached to the signal as a private struct object, or to some object reachable from it. Don’t worry about filtering for the “same train” cases, this is automatically done.&lt;br /&gt;
&lt;br /&gt;
If no reservation is desired, use the &amp;lt;code&amp;gt;empty&amp;lt;/code&amp;gt; global method available in all &amp;lt;code&amp;gt;ID&amp;amp;lt;Class&amp;amp;gt;&amp;lt;/code&amp;gt; types: &amp;lt;code&amp;gt;return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {}&lt;br /&gt;
struct Owner {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; {&lt;br /&gt;
    // some other, more full featured script function has attached Owner to this signal,&lt;br /&gt;
    // or not, so we need to check first&lt;br /&gt;
    if let owner &amp;amp;amp;= db.view&amp;amp;lt;Owner&amp;amp;gt;(signal) {&lt;br /&gt;
        if is_valid(db.view(owner.train_id)) {&lt;br /&gt;
            return owner.train_id;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_texture_state&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_texture_state ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_texture_state(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): i64 { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment, when the game UI needs to query what is the current signal texture state index, it will call your &amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt;, with some potential caching to keep the call rate lower. In any case the call rate of this function is potentially very large when the user zooms out the map, so make sure to keep its code as efficient as possible. For this same reason it is given very little access to the APIs.&lt;br /&gt;
&lt;br /&gt;
The return value indicates which signal texture state is to be used. If it’s -1 or lower, the default algorithm will be used to select the texture index. If it’s 0 or larger, it will select the texture in the same order as the &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; lines in the &amp;lt;code&amp;gt;SignalTextures&amp;lt;/code&amp;gt;. Larger values than the number of states will be clamped to the last state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_setup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_setup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_setup(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ss: &amp;amp;amp;mut ShiftSetup&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when an unassigned train decides to lookup a new shift to run, it will first call &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The parameter &amp;lt;code&amp;gt;ss&amp;lt;/code&amp;gt; is both an input and output parameter. It is initialized with the current, relevant data for the given train state, and &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; can then change it, to influence which shifts will be considered by the shift selection algorithm. It can change the train position used for matching, the time used for matching, and disable the check for reservations. For matched shifts which do not correspond to the current train position, the Extrapolator system will automatically pathfind a temporary milestone for the train, like other path-changing features.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_allow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_allow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_allow(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    run: &amp;amp;amp;Run,&lt;br /&gt;
    stop_idx: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    pose: &amp;amp;amp;Pose&lt;br /&gt;
): ShiftAllow { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when the shift selection algorithm fins a valid shift for the given train, it will call &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; with all the relevant data. The return of the function can then allow or deny the shift. If the shift is denied, the algorithm will resume immediately, trying other shifts&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are independent from each other, and can be used in any combination.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;controllers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Controllers ==&lt;br /&gt;
&lt;br /&gt;
Controller functions are called at a low frame rate compared to the overall simulation, with an (unchangeable) rate of once in 6 sim-seconds. In exchange they can invoke powerful ''commands'' as their execution result, and do not need any specific event or trigger to run, other than their enforced timer&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-control_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train control_train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct HateDepots extend Train {}&lt;br /&gt;
pub fn HateDepots::control_train(&lt;br /&gt;
    self: &amp;amp;amp;HateDepots,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    // train is already removed from the tracks, don't interfere with potential attempts at shift assignation&lt;br /&gt;
    if !is_valid(motion.presence.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is running a schedule, don't interfere&lt;br /&gt;
    if is_valid(motion.schedule_dispatch.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is present, but it is not running a schedule, so despawn it&lt;br /&gt;
    sc.queue_train_intervention(train);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The train motion engine will call train controllers after the entire simulation for a given frame is done, and all threads are finished. Command execution will only happen after all train controllers for a given frame are done. In other words, train controllers are given a consistent, read-only snapshot of the train sim, and queue up work to be executed by the sim. They never directly change the sim in any way, allowing train controller execution to be fully parallel.&lt;br /&gt;
&lt;br /&gt;
After all controllers are run, and all their non-task commands are executed, tasks are executed. Read more about tasks later on. Any tasks with a deadline which expired in this frame a run at this time too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontroller-command-queue&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== SimController command queue ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; object implements an API to control the simulation, including modification of some parameters and behaviors. It is also responsible for attaching and erasing private struct data from game objects, on behalf of scripts. The execution of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; is based on a command queue. Every call queues a command and returns immediately to the script code, without making any changes to the game state. Therefore the game state never changes while the script code is running.&lt;br /&gt;
&lt;br /&gt;
For control scripts, commands are executed asynchronously, there is no guaranteed order of execution! You must prepare your code and data for this design. For tasks scripts commands are executed in order and in isolation. You can queue up tasks from control scripts when you need to guarantee data consistency beyond “pick a random winner”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_intervention&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_intervention ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks, releases its schedule shift (if any), and deletes and refunds its pax (if any). No other cost other than pax refunds is issued. This function can be used as a general “despawn the train” feature, not just for exceptional circumstances.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_warp&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_warp ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks and repositions it at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, re-pathing it to its currently scheduled destination (if any), and setting its speed to 0. This is basically a train wormhole. The train keeps its shift and pax, if any.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_drive_to&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_drive_to ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Re-paths the train path to end at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, without any changes to its shift or pax (if any). It is possible for any future &amp;lt;code&amp;gt;queue_train_drive_to&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; to reset this path at any point, losing the destination. “Queue” here is used as part of the SimController API semantics, it does not mean the train keeps a queue of positions to reach. If the path is not interrupted and the train reaches &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; it will re-path itself towards its current scheduled stop, if it has any, or brake to a stop if unassigned. If &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; was also in the stop area set for its current scheduled stop it will also brake to stop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_attach&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_attach ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the attachment of the &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) to the &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt;, which must be of one of the following types: &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attached objects can be accessed with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt; at some point in the future. If called from a controller function, the attached object will be accessible after all controller functions are done for a given frame. If called from a task, he attached object will be accessible immediately after the task returns, and before any other task is executed. In other words, tasks are transaction-like, in the sense they view an immutable snapshot of the game state, and any changes they queue are executed before any other task, and then visible from these other tasks.&lt;br /&gt;
&lt;br /&gt;
Attaching an object of a given private struct type when it already exists attached to a &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt; will overwrite it. This is how private data is updated from scripting: by using &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; to copy any existing data, modifying the copy, then calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; to replace the existing data. Therefore it is a good idea to keep your private structs small. Only one instance of a given private struct type can be attached to any particular model object, but you can attach as many different private struct types as you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_erase&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_erase ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the erasure of &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt;, which must obtained using with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt;. Trying to erase temporary objects (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) is ignored. The execution of the queued erase commands is analog to the &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; case. In particular a sequences of attach and erase queued from controllers will produce undefined results (impossible to predict which attach and/or erase wins). For example multiple attach from a controller for the same model_obj and private struct type will implicitly pick a singular “winner” attach, but the script does not have any control over which one. Sequences of attach and erase queued from tasks are strictly ordered and isolated, so they produce consistent results, in the same order they were queued in the task script, without any concurrent changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task-and-simcontrollerqueue_task_at&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task and SimController::queue_task_at ===&lt;br /&gt;
&lt;br /&gt;
These functions are documented in the next section.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
Tasks are a very special kind of command which allows scripts to dynamically queue “future work”. Scripts with access to &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; can call this function to queue up a task for future script execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; must be of a private struct type which implements &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example { ... }&lt;br /&gt;
pub fn Example::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
For example, a train controller script could decide it needs to delay some decision into a task for data consistency reasons (other controllers are running at the same time), and delegate into a task rather than directly calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ControlTrain extend Train { ... }&lt;br /&gt;
pub fn ControlTrain::control_train(&lt;br /&gt;
    self: &amp;amp;amp;ControlTrain,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    task.train_id = train.id;&lt;br /&gt;
    task.v = some_data_from_somewhere;&lt;br /&gt;
    task.prio = 42; // or something smarter, like from ControlTrain, other objects, etc.&lt;br /&gt;
    sc.queue_task(task);&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
struct Task {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
struct SomeData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
pub fn Task::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    let train &amp;amp;amp;= ctx.db.view(self.train_id) else { return; }&lt;br /&gt;
    if let existing &amp;amp;amp;= ctx.db.view&amp;amp;lt;SomeData&amp;amp;gt;(train) {&lt;br /&gt;
        if existing.prio &amp;amp;gt;= self.prio {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    let data = SomeData::new();&lt;br /&gt;
    data.v = self.v;&lt;br /&gt;
    data.prio = self.prio;&lt;br /&gt;
    sc.queue_attach(train, data);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the previous example, maybe &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; will be called multiple times because multiple &amp;lt;code&amp;gt;ControlTrain::control_train()&amp;lt;/code&amp;gt; instances queued objects of &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;, but each execution will be single threaded, and all its queued &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; commands will be executed just after the call is done and before any other &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; call (for &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; or any other struct type), therefore the algorithm to pick a winner based on an explicit priority works.&lt;br /&gt;
&lt;br /&gt;
As mentioned, task execution is single threaded. The game does not feature a real concurrent database, instead all concurrent access is bespoke and very carefully designed to avoid deadlocks and inconsistencies (this is much faster than a general purpose concurrent database). Scripts also run in this parallel system, but their access to the game state is carefully restricted as explained earlier. But in the end, scripts also need to modify data, and do so in a consistent way. Tasks solve this issue, but do so in the most pessimistic possible way, by being single threaded. Therefore script developers should use them in moderation. Consider the “random winner” semantics of control script queuing first, which are completely free performance wise, before deciding you need a task. It is often the case a concurrent problem reduces to “pick 0 or 1 winners, any winner, but never 2 or more” and the default queue semantics already provide that guarantee for attaching a specific model/private pair.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; is provided with &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt;, therefore it can queue tasks itself. But unlike controller queuing tasks, which are guaranteed to run on the same frame, tasks queued from tasks are guaranteed to ''not'' run on the same frame, on purpose. They are deliberately stored away and forced a delay of 6 sim-seconds. This is to avoid misuse of tasks, and infinite looping.&lt;br /&gt;
&lt;br /&gt;
This behavior might even be desirable in certain scripts, for example if you are developing some stateful signal system and you need some kind of “cleanup” task that makes sure some signal being owned by some train is still the focus of said train. You can deliberately queue tasks for future simulation frames with &amp;lt;code&amp;gt;queue_task_at&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;deadline&amp;lt;/code&amp;gt; is expressed as microseconds since the start of the current save world. You can obtain the current simulation frame &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; value with &amp;lt;code&amp;gt;Extrapolator::clock_us()&amp;lt;/code&amp;gt;, like in this example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;    // schedule task to run 10 sim-s from now&lt;br /&gt;
    sc.queue_task_at(task, ctx.extrapolator.clock_us() + 10000000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-controlctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ControlCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ControlCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    sim: &amp;amp;amp;Sim,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim controller scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects, and associated script stuct objects.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::track_pos_project(self: &amp;amp;amp;DB, pos: &amp;amp;amp;Pos, distance: f64): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return a track position separated by ‘distance’ meters from ‘pos’, in the direction of ‘pos’. If distance is negative it will be in the opposite direction. Can only follow the main track. Merges and dead ends will return a Pos a shorter distance away. Signals are ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB): &amp;amp;amp;Script&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-eventctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type EventCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct EventCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim event handler scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    schedule_station_event: std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
    hitch: std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionhitch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Hitch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Hitch {&lt;br /&gt;
    driver_train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Train is being hitched by a driver train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestationevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStationEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStationEvent {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing scheduled stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-script&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Script ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Script {&lt;br /&gt;
    id: ID&amp;amp;lt;Script&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Shift {&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::kind(self: &amp;amp;amp;Signal): mut SignalKind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the signal kind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Hitch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;): *Motion::Hitch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStationEvent&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStationEvent&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Script&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Line&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::contains(&lt;br /&gt;
    self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;,&lt;br /&gt;
    value: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;&lt;br /&gt;
): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Schedule&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Signal&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-vecid-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::contains(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, value: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::get(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;, idx: i64): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::is_empty(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::iter(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::len(self: &amp;amp;amp;Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-veciditerator-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Vec&amp;amp;lt;ID&amp;lt;Train&amp;gt;&amp;amp;gt;::Iterator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator::next(self: &amp;amp;amp;mut Vec&amp;amp;lt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;amp;gt;::Iterator): *ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::clock_us(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current microseconds since the creation of this saved game. This is used as the timing root of the simulation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second since 1970-01-01:00:00:00.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_occupation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_reservation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying or reserving the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_occupying(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_reserving(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying or reserving the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
Probe a track position for train reservations and occupations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Seconds since 1970-01-01:00:00:00 for Monday 00:00:00 of the current week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
Advance the iterator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftallow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftAllow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftAllow {&lt;br /&gt;
    Allow,&lt;br /&gt;
    Deny,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftsetup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftSetup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ShiftSetup {&lt;br /&gt;
    skip: bool,&lt;br /&gt;
    match_pos: bool,&lt;br /&gt;
    check_occupation: bool,&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores the context of a train shift lookup.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function wants to change the train path, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signallookaheadresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalLookaheadResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalLookaheadResult {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores extra information associated with the result of the signal lookahead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-sim&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Sim ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Sim {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of the simulation state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Sim::view&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Sim, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A proxy mutable API to the simulation engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_hitch(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    driver: &amp;amp;amp;Train,&lt;br /&gt;
    hitcher: &amp;amp;amp;Train&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(self: &amp;amp;amp;mut SimController, train: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_configuration(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    config: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_unhitch(self: &amp;amp;amp;mut SimController, hitcher: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=548</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=548"/>
		<updated>2025-12-09T18:41:59Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used in game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration, integer division or arbitrary setting of pointers and references, and most data exposed to scripts is read-only, strictly enforced by the language. Any expression result which could result in an out of bounds or invalid memory access must be checked for validity, and the API design together with the type system enforces it.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
pub struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;SpeedTrap,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- VisMod? 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' NAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Script&amp;lt;/code&amp;gt; (with restrictions)&lt;br /&gt;
&lt;br /&gt;
Structs extending game types for player extensions must be declared as &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt;. When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
To read struct objects from script code they must be looked up using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API. Therefore only functions provided with &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt; object (or a context object with contains &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt;) can look up these objects. But you can pass around &amp;lt;code&amp;gt;DB&amp;amp;amp;&amp;lt;/code&amp;gt; as a parameter without any lifetime restrictions, since it’s a purely read only API. This API also works for non-pub structs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= ctx.db.view&amp;amp;lt;Example&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    log(&amp;amp;quot;v = @&amp;amp;quot;, config.v);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;pub-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== pub structs ====&lt;br /&gt;
&lt;br /&gt;
As explained earlier, &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs are the user interface of your scripts. They are exposed in the UI as input forms, and their &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;s can give some control over this rendering. Conceptually they are owned by the player of the game as part of the game object database, by attaching them to a game model object in the database, not the script. Scripts do not have any capability to create, edit or delete objects of &amp;lt;code&amp;gt;pub struct&amp;lt;/code&amp;gt;s. It is always the player who decides when to create a new object of these structs by interacting in the UI. Scripts can then read, and only read, the content of these objects, by using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API presented earlier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs have a very powerful capability: they have limited support for forward schema evolution. This means that the script developer can add to, and reorder, fields in &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, and the game runtime will be able keep the contents of the other fields intact. This is very important to respect the input data by the player. If you rename &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs or their fields, or change their types, the player input data will be lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;non-pub-or-private-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Non-pub (or private) structs ====&lt;br /&gt;
&lt;br /&gt;
Non-&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, also called private structs, are conceptually owned by the script as a part of the simulation, not the player. Their contents are assumed to be a black box by the rest of the game. Scripts are allowed to create and modify objects of these structs during their execution, which are automatically deleted at the end of the simulation frame. It is also possible to attach these structs to existing game model objects to extend their lifetime beyond the current frame. In this case their lifetime becomes the same as the game object, and they can be retrieved in later frames for reading, deleted or overwritten as desired.&lt;br /&gt;
&lt;br /&gt;
Private structs ''do not support schema evolution''. Changing field types, field names, reordering of fields, even just adding new fields at the end, will always result in losing all existing attached objects of the given struct. Some operations like resetting the simulation will also erase attached objects, because they are considered simulation state, not player created objects.&lt;br /&gt;
&lt;br /&gt;
Private structs support dynamic memory allocation. All private struct definitions automatically create a &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; method for the struct:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct PrivData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let ro &amp;amp;amp;= ctx.db.view&amp;amp;lt;PrivData&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    let rw &amp;amp;amp;mut= PrivData::clone(ro);&lt;br /&gt;
    rw.v = 100;&lt;br /&gt;
    let empty &amp;amp;amp;mut= PrivData::new();&lt;br /&gt;
    empty.v = 200;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The objects allocated by &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; are always deleted at the end of the current simulation frame. Their lifetime can be extended beyond the current frame by attaching them to a game object, like &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, so their lifetime becomes the same as the attached object. The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API has methods for attaching and erasing these object.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;host-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Host structs ====&lt;br /&gt;
&lt;br /&gt;
Many of the exposed game APIs are also based around structs. These structs do not follow any of the previous rules. Some have special capabilities, for example simple structs like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt; are ''value objects'': they can be copied and passed around like any &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; would. Some others are strictly locked down and serve as very little beyond a way to keep a pointer safe. In general, when working with game API structs, assume they are what would be called ''move only'' in C++. And NimbyScript has no move operator or semantics, so in essence assume they are immutable, immobile references, except when documented otherwise (like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As an aside, all script declared &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; or not) are also always ''move only'', and always “owned” by some external entity. This is why the APIs for their manipulation are always based on pointers and references, even for private structs. It is not possible to create plain, stack allocated values of script structs, or to use them as fields in structs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version:&lt;br /&gt;
&lt;br /&gt;
* Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
* Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums)&lt;br /&gt;
* For pub structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* For private structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In pub structs these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- 'let' BindBody 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- 'let' BindBody ';'&lt;br /&gt;
BindBody    &amp;amp;lt;- NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' 'let' BindBody BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- ColonNAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere, pointer types cannot be deferenced, therefore cannot be used in dot expressions. But built-in functions &amp;lt;code&amp;gt;is_null(v): bool&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;is_valid(v): bool&amp;lt;/code&amp;gt; are usable with any pointer type and value.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;extensions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Extensions =&lt;br /&gt;
&lt;br /&gt;
Extending game database struct data with &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt; can also be used to extend the game code. The mechanism to do so is to first declare a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;ing a game database object (with or without fields). Then create a specifically named and parametrized function which will be called by the game under certain situations, for certain kinds of objects.&lt;br /&gt;
&lt;br /&gt;
All extension functions take a &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter which is a reference to the struct which it is method of, called &amp;lt;code&amp;gt;Example&amp;lt;/code&amp;gt; in the following sections. Replace it with your struct name. The rest of the parameters are fixed and must be reproduced exactly as-is.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
Event functions are called as part of the core simulation engine. They are meant to be focused in features and quick to execute. These functions might be called thousands of times per simulation frame, including multiple redundant times. Their capability to change the simulation behavior is usually very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_check&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_check ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails, or if another script call returns &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_lookahead&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_lookahead ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_lookahead(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    train_distance: f64,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalLookaheadResult&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; function at regular intervals for each signal 15km ahead of the train path. It is called for all signals, until one of these conditions hold: - One of the signals path checks as &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; - Another train is found - The train stop is found - 15km have been checked&lt;br /&gt;
&lt;br /&gt;
For both &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; signals, your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; will be called, and you can check the path find result in &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;, and the distance from the train in &amp;lt;code&amp;gt;train_distance&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; allows to set a maximum speed for the train, which goes into effect immediately. This works from any distance and past any amount of signals between the train and the caller signal. If multiple signals in the lookahead path return a &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt;, the slowest speed is picked. If no &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt; is set, or it is 0, the result is ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; default value is 0, which is considered invalid and will be ignored. To stop the train at the signal implement &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_change_path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_change_path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_change_path(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The current path check result of this signal for the passed train is passed as &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;. This already includes any results from &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_pass_by&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_pass_by ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_pass_by(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; function on the exact simulation frame a train passes by the exact point of the signal on the track.&lt;br /&gt;
&lt;br /&gt;
This function has no return result. Instead, since it has a predictably low call rate compared to the other events, it is the only event function with access to the powerful &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_marker_reserved&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_marker_reserved ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given marker signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; any time the reservation check algorithm is tracing a path which goes over the marker signal, on any direction, giving it the chance to report an arbitrary train as the reserver of that point on the track.&lt;br /&gt;
&lt;br /&gt;
This signal has a potential huge call rate, and for this reason it is given very little access to the APIs. The intention is that all the state required by this signal is calculated somewhere else and attached to the signal as a private struct object, or to some object reachable from it. Don’t worry about filtering for the “same train” cases, this is automatically done.&lt;br /&gt;
&lt;br /&gt;
If no reservation is desired, use the &amp;lt;code&amp;gt;empty&amp;lt;/code&amp;gt; global method available in all &amp;lt;code&amp;gt;ID&amp;amp;lt;Class&amp;amp;gt;&amp;lt;/code&amp;gt; types: &amp;lt;code&amp;gt;return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal {}&lt;br /&gt;
struct Owner {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; {&lt;br /&gt;
    // some other, more full featured script function has attached Owner to this signal,&lt;br /&gt;
    // or not, so we need to check first&lt;br /&gt;
    if let owner &amp;amp;amp;= db.view&amp;amp;lt;Owner&amp;amp;gt;(signal) {&lt;br /&gt;
        if is_valid(db.view(owner.train_id)) {&lt;br /&gt;
            return owner.train_id;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_texture_state&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_texture_state ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_texture_state(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): i64 { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment, when the game UI needs to query what is the current signal texture state index, it will call your &amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt;, with some potential caching to keep the call rate lower. In any case the call rate of this function is potentially very large when the user zooms out the map, so make sure to keep its code as efficient as possible. For this same reason it is given very little access to the APIs.&lt;br /&gt;
&lt;br /&gt;
The return value indicates which signal texture state is to be used. If it’s -1 or lower, the default algorithm will be used to select the texture index. If it’s 0 or larger, it will select the texture in the same order as the &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; lines in the &amp;lt;code&amp;gt;SignalTextures&amp;lt;/code&amp;gt;. Larger values than the number of states will be clamped to the last state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_setup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_setup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_setup(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ss: &amp;amp;amp;mut ShiftSetup&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when an unassigned train decides to lookup a new shift to run, it will first call &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The parameter &amp;lt;code&amp;gt;ss&amp;lt;/code&amp;gt; is both an input and output parameter. It is initialized with the current, relevant data for the given train state, and &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; can then change it, to influence which shifts will be considered by the shift selection algorithm. It can change the train position used for matching, the time used for matching, and disable the check for reservations. For matched shifts which do not correspond to the current train position, the Extrapolator system will automatically pathfind a temporary milestone for the train, like other path-changing features.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_allow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_allow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_allow(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    run: &amp;amp;amp;Run,&lt;br /&gt;
    stop_idx: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    pose: &amp;amp;amp;Pose&lt;br /&gt;
): ShiftAllow { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when the shift selection algorithm fins a valid shift for the given train, it will call &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; with all the relevant data. The return of the function can then allow or deny the shift. If the shift is denied, the algorithm will resume immediately, trying other shifts&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are independent from each other, and can be used in any combination.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;controllers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Controllers ==&lt;br /&gt;
&lt;br /&gt;
Controller functions are called at a low frame rate compared to the overall simulation, with an (unchangeable) rate of once in 6 sim-seconds. In exchange they can invoke powerful ''commands'' as their execution result, and do not need any specific event or trigger to run, other than their enforced timer&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-control_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train control_train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct HateDepots extend Train {}&lt;br /&gt;
pub fn HateDepots::control_train(&lt;br /&gt;
    self: &amp;amp;amp;HateDepots,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    // train is already removed from the tracks, don't interfere with potential attempts at shift assignation&lt;br /&gt;
    if is_null(motion.presence.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is running a schedule, don't interfere&lt;br /&gt;
    if is_valid(motion.schedule_dispatch.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is present, but it is not running a schedule, so despawn it&lt;br /&gt;
    sc.queue_train_intervention(train);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The train motion engine will call train controllers after the entire simulation for a given frame is done, and all threads are finished. Command execution will only happen after all train controllers for a given frame are done. In other words, train controllers are given a consistent, read-only snapshot of the train sim, and queue up work to be executed by the sim. They never directly change the sim in any way, allowing train controller execution to be fully parallel.&lt;br /&gt;
&lt;br /&gt;
After all controllers are run, and all their non-task commands are executed, tasks are executed. Read more about tasks later on. Any tasks with a deadline which expired in this frame a run at this time too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontroller-command-queue&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== SimController command queue ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; object implements an API to control the simulation, including modification of some parameters and behaviors. It is also responsible for attaching and erasing private struct data from game objects, on behalf of scripts. The execution of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; is based on a command queue. Every call queues a command and returns immediately to the script code, without making any changes to the game state. Therefore the game state never changes while the script code is running.&lt;br /&gt;
&lt;br /&gt;
For control scripts, commands are executed asynchronously, there is no guaranteed order of execution! You must prepare your code and data for this design. For tasks scripts commands are executed in order and in isolation. You can queue up tasks from control scripts when you need to guarantee data consistency beyond “pick a random winner”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_intervention&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_intervention ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks, releases its schedule shift (if any), and deletes and refunds its pax (if any). No other cost other than pax refunds is issued. This function can be used as a general “despawn the train” feature, not just for exceptional circumstances.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_warp&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_warp ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks and repositions it at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, re-pathing it to its currently scheduled destination (if any), and setting its speed to 0. This is basically a train wormhole. The train keeps its shift and pax, if any.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_drive_to&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_drive_to ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Re-paths the train path to end at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, without any changes to its shift or pax (if any). It is possible for any future &amp;lt;code&amp;gt;queue_train_drive_to&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; to reset this path at any point, losing the destination. “Queue” here is used as part of the SimController API semantics, it does not mean the train keeps a queue of positions to reach. If the path is not interrupted and the train reaches &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; it will re-path itself towards its current scheduled stop, if it has any, or brake to a stop if unassigned. If &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; was also in the stop area set for its current scheduled stop it will also brake to stop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_attach&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_attach ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the attachment of the &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) to the &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt;, which must be of one of the following types: &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attached objects can be accessed with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt; at some point in the future. If called from a controller function, the attached object will be accessible after all controller functions are done for a given frame. If called from a task, he attached object will be accessible immediately after the task returns, and before any other task is executed. In other words, tasks are transaction-like, in the sense they view an immutable snapshot of the game state, and any changes they queue are executed before any other task, and then visible from these other tasks.&lt;br /&gt;
&lt;br /&gt;
Attaching an object of a given private struct type when it already exists attached to a &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt; will overwrite it. This is how private data is updated from scripting: by using &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; to copy any existing data, modifying the copy, then calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; to replace the existing data. Therefore it is a good idea to keep your private structs small. Only one instance of a given private struct type can be attached to any particular model object, but you can attach as many different private struct types as you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_erase&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_erase ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the erasure of &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt;, which must obtained using with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt;. Trying to erase temporary objects (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) is ignored. The execution of the queued erase commands is analog to the &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; case. In particular a sequences of attach and erase queued from controllers will produce undefined results (impossible to predict which attach and/or erase wins). For example multiple attach from a controller for the same model_obj and private struct type will implicitly pick a singular “winner” attach, but the script does not have any control over which one. Sequences of attach and erase queued from tasks are strictly ordered and isolated, so they produce consistent results, in the same order they were queued in the task script, without any concurrent changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task-and-simcontrollerqueue_task_at&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task and SimController::queue_task_at ===&lt;br /&gt;
&lt;br /&gt;
These functions are documented in the next section.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
Tasks are a very special kind of command which allows scripts to dynamically queue “future work”. Scripts with access to &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; can call this function to queue up a task for future script execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; must be of a private struct type which implements &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example { ... }&lt;br /&gt;
pub fn Example::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
For example, a train controller script could decide it needs to delay some decision into a task for data consistency reasons (other controllers are running at the same time), and delegate into a task rather than directly calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ControlTrain extends Train { ... }&lt;br /&gt;
pub fn ControlTrain::control_train(&lt;br /&gt;
    self: &amp;amp;amp;ControlTrain,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    task.train_id = train.id;&lt;br /&gt;
    task.v = some_data_from_somewhere;&lt;br /&gt;
    task.prio = 42; // or something smarter, like from ControlTrain, other objects, etc.&lt;br /&gt;
    sc.queue_task(task);&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
struct Task {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
struct SomeData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
pub fn Task::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    let train &amp;amp;amp;= ctx.db.view(self.train_id) else { return; }&lt;br /&gt;
    if let existing &amp;amp;amp;= ctx.db.view&amp;amp;lt;SomeData&amp;amp;gt;(train) {&lt;br /&gt;
        if existing.prio &amp;amp;gt;= self.prio {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    let data = SomeData::new();&lt;br /&gt;
    data.v = self.v;&lt;br /&gt;
    data.prio = self.prio;&lt;br /&gt;
    sc.queue_attach(train, data);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the previous example, maybe &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; will be called multiple times because multiple &amp;lt;code&amp;gt;ControlTrain::control_train()&amp;lt;/code&amp;gt; instances queued objects of &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;, but each execution will be single threaded, and all its queued &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; commands will be executed just after the call is done and before any other &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; call (for &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; or any other struct type), therefore the algorithm to pick a winner based on an explicit priority works.&lt;br /&gt;
&lt;br /&gt;
As mentioned, task execution is single threaded. The game does not feature a real concurrent database, instead all concurrent access is bespoke and very carefully designed to avoid deadlocks and inconsistencies (this is much faster than a general purpose concurrent database). Scripts also run in this parallel system, but their access to the game state is carefully restricted as explained earlier. But in the end, scripts also need to modify data, and do so in a consistent way. Tasks solve this issue, but do so in the most pessimistic possible way, by being single threaded. Therefore script developers should use them in moderation. Consider the “random winner” semantics of control script queuing first, which are completely free performance wise, before deciding you need a task. It is often the case a concurrent problem reduces to “pick 0 or 1 winners, any winner, but never 2 or more” and the default queue semantics already provide that guarantee for attaching a specific model/private pair.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; is provided with &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt;, therefore it can queue tasks itself. But unlike controller queuing tasks, which are guaranteed to run on the same frame, tasks queued from tasks are guaranteed to ''not'' run on the same frame, on purpose. They are deliberately stored away and forced a delay of 6 sim-seconds. This is to avoid misuse of tasks, and infinite looping.&lt;br /&gt;
&lt;br /&gt;
This behavior might even be desirable in certain scripts, for example if you are developing some stateful signal system and you need some kind of “cleanup” task that makes sure some signal being owned by some train is still the focus of said train. You can deliberately queue tasks for future simulation frames with &amp;lt;code&amp;gt;queue_task_at&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;deadline&amp;lt;/code&amp;gt; is expressed as microseconds since the start of the current save world. You can obtain the current simulation frame &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; value with &amp;lt;code&amp;gt;Extrapolator::clock_us()&amp;lt;/code&amp;gt;, like in this example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;    // schedule task to run 10 sim-s from now&lt;br /&gt;
    sc.queue_task_at(task, ctx.extrapolator.clock_us() + 10000000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-controlctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ControlCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ControlCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    sim: &amp;amp;amp;Sim,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim controller scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects, and associated script stuct objects.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB): &amp;amp;amp;Script&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-eventctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type EventCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct EventCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim event handler scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    schedule_station_event: std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
    hitch: std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionhitch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Hitch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Hitch {&lt;br /&gt;
    driver_train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Train is being hitched by a driver train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestationevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStationEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStationEvent {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing scheduled stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-script&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Script ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Script {&lt;br /&gt;
    id: ID&amp;amp;lt;Script&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Shift {&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::kind(self: &amp;amp;amp;Signal): mut SignalKind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the signal kind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Hitch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Hitch&amp;amp;gt;): *Motion::Hitch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStationEvent&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStationEvent&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Script&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::clock_us(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current microseconds since the creation of this saved game. This is used as the timing root of the simulation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second since 1970-01-01:00:00:00.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_occupation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::get_one_reservation(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    ignore_train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return any train currently occupying or reserving the given position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_occupying(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::is_reserving(&lt;br /&gt;
    self: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    pos: &amp;amp;amp;Pos,&lt;br /&gt;
    train: ID&amp;amp;lt;Train&amp;amp;gt;&lt;br /&gt;
): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return true if the given train is occupying or reserving the position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
Probe a track position for train reservations and occupations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Seconds since 1970-01-01:00:00:00 for Monday 00:00:00 of the current week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
Advance the iterator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftallow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftAllow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftAllow {&lt;br /&gt;
    Allow,&lt;br /&gt;
    Deny,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftsetup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftSetup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ShiftSetup {&lt;br /&gt;
    skip: bool,&lt;br /&gt;
    match_pos: bool,&lt;br /&gt;
    check_occupation: bool,&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores the context of a train shift lookup.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function wants to change the train path, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signallookaheadresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalLookaheadResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalLookaheadResult {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores extra information associated with the result of the signal lookahead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-sim&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Sim ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Sim {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of the simulation state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Sim::view&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Sim, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A proxy mutable API to the simulation engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_hitch(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    driver: &amp;amp;amp;Train,&lt;br /&gt;
    hitcher: &amp;amp;amp;Train&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(self: &amp;amp;amp;mut SimController, train: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_set_configuration(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    config: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_unhitch(self: &amp;amp;amp;mut SimController, hitcher: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=547</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=547"/>
		<updated>2025-12-04T11:09:10Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used in game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration, integer division or arbitrary setting of pointers and references, and most data exposed to scripts is read-only, strictly enforced by the language. Any expression result which could result in an out of bounds or invalid memory access must be checked for validity, and the API design together with the type system enforces it.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
pub struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;SpeedTrap,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- VisMod? 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' NAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Script&amp;lt;/code&amp;gt; (with restrictions)&lt;br /&gt;
&lt;br /&gt;
Structs extending game types for player extensions must be declared as &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt;. When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
To read struct objects from script code they must be looked up using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API. Therefore only functions provided with &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt; object (or a context object with contains &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt;) can look up these objects. But you can pass around &amp;lt;code&amp;gt;DB&amp;amp;amp;&amp;lt;/code&amp;gt; as a parameter without any lifetime restrictions, since it’s a purely read only API. This API also works for non-pub structs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= ctx.db.view&amp;amp;lt;Example&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    log(&amp;amp;quot;v = @&amp;amp;quot;, config.v);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;pub-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== pub structs ====&lt;br /&gt;
&lt;br /&gt;
As explained earlier, &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs are the user interface of your scripts. They are exposed in the UI as input forms, and their &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;s can give some control over this rendering. Conceptually they are owned by the player of the game as part of the game object database, by attaching them to a game model object in the database, not the script. Scripts do not have any capability to create, edit or delete objects of &amp;lt;code&amp;gt;pub struct&amp;lt;/code&amp;gt;s. It is always the player who decides when to create a new object of these structs by interacting in the UI. Scripts can then read, and only read, the content of these objects, by using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API presented earlier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs have a very powerful capability: they have limited support for forward schema evolution. This means that the script developer can add to, and reorder, fields in &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, and the game runtime will be able keep the contents of the other fields intact. This is very important to respect the input data by the player. If you rename &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs or their fields, or change their types, the player input data will be lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;non-pub-or-private-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Non-pub (or private) structs ====&lt;br /&gt;
&lt;br /&gt;
Non-&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, also called private structs, are conceptually owned by the script as a part of the simulation, not the player. Their contents are assumed to be a black box by the rest of the game. Scripts are allowed to create and modify objects of these structs during their execution, which are automatically deleted at the end of the simulation frame. It is also possible to attach these structs to existing game model objects to extend their lifetime beyond the current frame. In this case their lifetime becomes the same as the game object, and they can be retrieved in later frames for reading, deleted or overwritten as desired.&lt;br /&gt;
&lt;br /&gt;
Private structs ''do not support schema evolution''. Changing field types, field names, reordering of fields, even just adding new fields at the end, will always result in losing all existing attached objects of the given struct. Some operations like resetting the simulation will also erase attached objects, because they are considered simulation state, not player created objects.&lt;br /&gt;
&lt;br /&gt;
Private structs support dynamic memory allocation. All private struct definitions automatically create a &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; method for the struct:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct PrivData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let ro &amp;amp;amp;= ctx.db.view&amp;amp;lt;PrivData&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    let rw &amp;amp;amp;mut= PrivData::clone(ro);&lt;br /&gt;
    rw.v = 100;&lt;br /&gt;
    let empty &amp;amp;amp;mut= PrivData::new();&lt;br /&gt;
    empty.v = 200;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The objects allocated by &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; are always deleted at the end of the current simulation frame. Their lifetime can be extended beyond the current frame by attaching them to a game object, like &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, so their lifetime becomes the same as the attached object. The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API has methods for attaching and erasing these object.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;host-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Host structs ====&lt;br /&gt;
&lt;br /&gt;
Many of the exposed game APIs are also based around structs. These structs do not follow any of the previous rules. Some have special capabilities, for example simple structs like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt; are ''value objects'': they can be copied and passed around like any &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; would. Some others are strictly locked down and serve as very little beyond a way to keep a pointer safe. In general, when working with game API structs, assume they are what would be called ''move only'' in C++. And NimbyScript has no move operator or semantics, so in essence assume they are immutable, immobile references, except when documented otherwise (like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As an aside, all script declared &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; or not) are also always ''move only'', and always “owned” by some external entity. This is why the APIs for their manipulation are always based on pointers and references, even for private structs. It is not possible to create plain, stack allocated values of script structs, or to use them as fields in structs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version:&lt;br /&gt;
&lt;br /&gt;
* Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
* Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums)&lt;br /&gt;
* For pub structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* For private structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In pub structs these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- 'let' BindBody 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- 'let' BindBody ';'&lt;br /&gt;
BindBody    &amp;amp;lt;- NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' 'let' BindBody BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- ColonNAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere, pointer types cannot be deferenced, therefore cannot be used in dot expressions. But built-in functions &amp;lt;code&amp;gt;is_null(v): bool&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;is_valid(v): bool&amp;lt;/code&amp;gt; are usable with any pointer type and value.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;extensions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Extensions =&lt;br /&gt;
&lt;br /&gt;
Extending game database struct data with &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt; can also be used to extend the game code. The mechanism to do so is to first declare a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;ing a game database object (with or without fields). Then create a specifically named and parametrized function which will be called by the game under certain situations, for certain kinds of objects.&lt;br /&gt;
&lt;br /&gt;
All extension functions take a &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter which is a reference to the struct which it is method of, called &amp;lt;code&amp;gt;Example&amp;lt;/code&amp;gt; in the following sections. Replace it with your struct name. The rest of the parameters are fixed and must be reproduced exactly as-is.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
Event functions are called as part of the core simulation engine. They are meant to be focused in features and quick to execute. These functions might be called thousands of times per simulation frame, including multiple redundant times. Their capability to change the simulation behavior is usually very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_check&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_check ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails, or if another script call returns &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_lookahead&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_lookahead ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_lookahead(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    train_distance: f64,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalLookaheadResult&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; function at regular intervals for each signal 15km ahead of the train path. It is called for all signals, until one of these conditions hold: - One of the signals path checks as &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; - Another train is found - The train stop is found - 15km have been checked&lt;br /&gt;
&lt;br /&gt;
For both &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; signals, your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; will be called, and you can check the path find result in &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;, and the distance from the train in &amp;lt;code&amp;gt;train_distance&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; allows to set a maximum speed for the train, which goes into effect immediately. This works from any distance and past any amount of signals between the train and the caller signal. If multiple signals in the lookahead path return a &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt;, the slowest speed is picked. If no &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt; is set, or it is 0, the result is ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; default value is 0, which is considered invalid and will be ignored. To stop the train at the signal implement &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_change_path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_change_path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_change_path(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The current path check result of this signal for the passed train is passed as &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;. This already includes any results from &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_pass_by&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_pass_by ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_pass_by(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; function on the exact simulation frame a train passes by the exact point of the signal on the track.&lt;br /&gt;
&lt;br /&gt;
This function has no return result. Instead, since it has a predictably low call rate compared to the other events, it is the only event function with access to the powerful &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_marker_reserved&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_marker_reserved ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given marker signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; any time the reservation check algorithm is tracing a path which goes over the marker signal, on any direction, giving it the chance to report an arbitrary train as the reserver of that point on the track.&lt;br /&gt;
&lt;br /&gt;
This signal has a potential huge call rate, and for this reason it is given very little access to the APIs. The intention is that all the state required by this signal is calculated somewhere else and attached to the signal as a private struct object, or to some object reachable from it. Don’t worry about filtering for the “same train” cases, this is automatically done.&lt;br /&gt;
&lt;br /&gt;
If no reservation is desired, use the &amp;lt;code&amp;gt;empty&amp;lt;/code&amp;gt; global method available in all &amp;lt;code&amp;gt;ID&amp;amp;lt;Class&amp;amp;gt;&amp;lt;/code&amp;gt; types: &amp;lt;code&amp;gt;return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal {}&lt;br /&gt;
struct Owner {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; {&lt;br /&gt;
    // some other, more full featured script function has attached Owner to this signal,&lt;br /&gt;
    // or not, so we need to check first&lt;br /&gt;
    if let owner &amp;amp;amp;= db.view&amp;amp;lt;Owner&amp;amp;gt;(signal) {&lt;br /&gt;
        if is_valid(db.view(owner.train_id)) {&lt;br /&gt;
            return owner.train_id;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_texture_state&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_texture_state ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_texture_state(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): i64 { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment, when the game UI needs to query what is the current signal texture state index, it will call your &amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt;, with some potential caching to keep the call rate lower. In any case the call rate of this function is potentially very large when the user zooms out the map, so make sure to keep its code as efficient as possible. For this same reason it is given very little access to the APIs.&lt;br /&gt;
&lt;br /&gt;
The return value indicates which signal texture state is to be used. If it’s -1 or lower, the default algorithm will be used to select the texture index. If it’s 0 or larger, it will select the texture in the same order as the &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; lines in the &amp;lt;code&amp;gt;SignalTextures&amp;lt;/code&amp;gt;. Larger values than the number of states will be clamped to the last state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_setup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_setup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_setup(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    ss: &amp;amp;amp;mut ShiftSetup&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when an unassigned train decides to lookup a new shift to run, it will first call &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The parameter &amp;lt;code&amp;gt;ss&amp;lt;/code&amp;gt; is both an input and output parameter. It is initialized with the current, relevant data for the given train state, and &amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; can then change it, to influence which shifts will be considered by the shift selection algorithm. It can change the train position used for matching, the time used for matching, and disable the check for reservations. For matched shifts which do not correspond to the current train position, the Extrapolator system will automatically pathfind a temporary milestone for the train, like other path-changing features.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-event_train_shift_allow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train event_train_shift_allow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Train { }&lt;br /&gt;
pub fn Example::event_train_shift_allow(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sched: &amp;amp;amp;Schedule,&lt;br /&gt;
    shift: &amp;amp;amp;Shift,&lt;br /&gt;
    run: &amp;amp;amp;Run,&lt;br /&gt;
    stop_idx: i64,&lt;br /&gt;
    arrival_us: i64,&lt;br /&gt;
    pose: &amp;amp;amp;Pose&lt;br /&gt;
): ShiftAllow { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given train in the train editor. From that moment, when the shift selection algorithm fins a valid shift for the given train, it will call &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; with all the relevant data. The return of the function can then allow or deny the shift. If the shift is denied, the algorithm will resume immediately, trying other shifts&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_train_shift_setup&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;event_train_shift_allow&amp;lt;/code&amp;gt; are independent from each other, and can be used in any combination.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;controllers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Controllers ==&lt;br /&gt;
&lt;br /&gt;
Controller functions are called at a low frame rate compared to the overall simulation, with an (unchangeable) rate of once in 6 sim-seconds. In exchange they can invoke powerful ''commands'' as their execution result, and do not need any specific event or trigger to run, other than their enforced timer&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-control_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train control_train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct HateDepots extend Train {}&lt;br /&gt;
pub fn HateDepots::control_train(&lt;br /&gt;
    self: &amp;amp;amp;HateDepots,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    // train is already removed from the tracks, don't interfere with potential attempts at shift assignation&lt;br /&gt;
    if is_null(motion.presence.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is running a schedule, don't interfere&lt;br /&gt;
    if is_valid(motion.schedule_dispatch.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is present, but it is not running a schedule, so despawn it&lt;br /&gt;
    sc.queue_train_intervention(train);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The train motion engine will call train controllers after the entire simulation for a given frame is done, and all threads are finished. Command execution will only happen after all train controllers for a given frame are done. In other words, train controllers are given a consistent, read-only snapshot of the train sim, and queue up work to be executed by the sim. They never directly change the sim in any way, allowing train controller execution to be fully parallel.&lt;br /&gt;
&lt;br /&gt;
After all controllers are run, and all their non-task commands are executed, tasks are executed. Read more about tasks later on. Any tasks with a deadline which expired in this frame a run at this time too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontroller-command-queue&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== SimController command queue ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; object implements an API to control the simulation, including modification of some parameters and behaviors. It is also responsible for attaching and erasing private struct data from game objects, on behalf of scripts. The execution of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; is based on a command queue. Every call queues a command and returns immediately to the script code, without making any changes to the game state. Therefore the game state never changes while the script code is running.&lt;br /&gt;
&lt;br /&gt;
For control scripts, commands are executed asynchronously, there is no guaranteed order of execution! You must prepare your code and data for this design. For tasks scripts commands are executed in order and in isolation. You can queue up tasks from control scripts when you need to guarantee data consistency beyond “pick a random winner”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_intervention&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_intervention ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks, releases its schedule shift (if any), and deletes and refunds its pax (if any). No other cost other than pax refunds is issued. This function can be used as a general “despawn the train” feature, not just for exceptional circumstances.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_warp&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_warp ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks and repositions it at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, re-pathing it to its currently scheduled destination (if any), and setting its speed to 0. This is basically a train wormhole. The train keeps its shift and pax, if any.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_drive_to&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_drive_to ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Re-paths the train path to end at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, without any changes to its shift or pax (if any). It is possible for any future &amp;lt;code&amp;gt;queue_train_drive_to&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; to reset this path at any point, losing the destination. “Queue” here is used as part of the SimController API semantics, it does not mean the train keeps a queue of positions to reach. If the path is not interrupted and the train reaches &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; it will re-path itself towards its current scheduled stop, if it has any, or brake to a stop if unassigned. If &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; was also in the stop area set for its current scheduled stop it will also brake to stop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_attach&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_attach ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the attachment of the &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) to the &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt;, which must be of one of the following types: &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attached objects can be accessed with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt; at some point in the future. If called from a controller function, the attached object will be accessible after all controller functions are done for a given frame. If called from a task, he attached object will be accessible immediately after the task returns, and before any other task is executed. In other words, tasks are transaction-like, in the sense they view an immutable snapshot of the game state, and any changes they queue are executed before any other task, and then visible from these other tasks.&lt;br /&gt;
&lt;br /&gt;
Attaching an object of a given private struct type when it already exists attached to a &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt; will overwrite it. This is how private data is updated from scripting: by using &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; to copy any existing data, modifying the copy, then calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; to replace the existing data. Therefore it is a good idea to keep your private structs small. Only one instance of a given private struct type can be attached to any particular model object, but you can attach as many different private struct types as you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_erase&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_erase ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the erasure of &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt;, which must obtained using with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt;. Trying to erase temporary objects (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) is ignored. The execution of the queued erase commands is analog to the &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; case. In particular a sequences of attach and erase queued from controllers will produce undefined results (impossible to predict which attach and/or erase wins). For example multiple attach from a controller for the same model_obj and private struct type will implicitly pick a singular “winner” attach, but the script does not have any control over which one. Sequences of attach and erase queued from tasks are strictly ordered and isolated, so they produce consistent results, in the same order they were queued in the task script, without any concurrent changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task-and-simcontrollerqueue_task_at&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task and SimController::queue_task_at ===&lt;br /&gt;
&lt;br /&gt;
These functions are documented in the next section.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
Tasks are a very special kind of command which allows scripts to dynamically queue “future work”. Scripts with access to &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; can call this function to queue up a task for future script execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; must be of a private struct type which implements &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example { ... }&lt;br /&gt;
pub fn Example::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
For example, a train controller script could decide it needs to delay some decision into a task for data consistency reasons (other controllers are running at the same time), and delegate into a task rather than directly calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ControlTrain extends Train { ... }&lt;br /&gt;
pub fn ControlTrain::control_train(&lt;br /&gt;
    self: &amp;amp;amp;ControlTrain,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    task.train_id = train.id;&lt;br /&gt;
    task.v = some_data_from_somewhere;&lt;br /&gt;
    task.prio = 42; // or something smarter, like from ControlTrain, other objects, etc.&lt;br /&gt;
    sc.queue_task(task);&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
struct Task {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
struct SomeData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
pub fn Task::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    let train &amp;amp;amp;= ctx.db.view(self.train_id) else { return; }&lt;br /&gt;
    if let existing &amp;amp;amp;= ctx.db.view&amp;amp;lt;SomeData&amp;amp;gt;(train) {&lt;br /&gt;
        if existing.prio &amp;amp;gt;= self.prio {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    let data = SomeData::new();&lt;br /&gt;
    data.v = self.v;&lt;br /&gt;
    data.prio = self.prio;&lt;br /&gt;
    sc.queue_attach(train, data);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the previous example, maybe &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; will be called multiple times because multiple &amp;lt;code&amp;gt;ControlTrain::control_train()&amp;lt;/code&amp;gt; instances queued objects of &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;, but each execution will be single threaded, and all its queued &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; commands will be executed just after the call is done and before any other &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; call (for &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; or any other struct type), therefore the algorithm to pick a winner based on an explicit priority works.&lt;br /&gt;
&lt;br /&gt;
As mentioned, task execution is single threaded. The game does not feature a real concurrent database, instead all concurrent access is bespoke and very carefully designed to avoid deadlocks and inconsistencies (this is much faster than a general purpose concurrent database). Scripts also run in this parallel system, but their access to the game state is carefully restricted as explained earlier. But in the end, scripts also need to modify data, and do so in a consistent way. Tasks solve this issue, but do so in the most pessimistic possible way, by being single threaded. Therefore script developers should use them in moderation. Consider the “random winner” semantics of control script queuing first, which are completely free performance wise, before deciding you need a task. It is often the case a concurrent problem reduces to “pick 0 or 1 winners, any winner, but never 2 or more” and the default queue semantics already provide that guarantee for attaching a specific model/private pair.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; is provided with &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt;, therefore it can queue tasks itself. But unlike controller queuing tasks, which are guaranteed to run on the same frame, tasks queued from tasks are guaranteed to ''not'' run on the same frame, on purpose. They are deliberately stored away and forced a delay of 6 sim-seconds. This is to avoid misuse of tasks, and infinite looping.&lt;br /&gt;
&lt;br /&gt;
This behavior might even be desirable in certain scripts, for example if you are developing some stateful signal system and you need some kind of “cleanup” task that makes sure some signal being owned by some train is still the focus of said train. You can deliberately queue tasks for future simulation frames with &amp;lt;code&amp;gt;queue_task_at&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;deadline&amp;lt;/code&amp;gt; is expressed as microseconds since the start of the current save world. You can obtain the current simulation frame &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; value with &amp;lt;code&amp;gt;Extrapolator::clock_us()&amp;lt;/code&amp;gt;, like in this example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;    // schedule task to run 10 sim-s from now&lt;br /&gt;
    sc.queue_task_at(task, ctx.extrapolator.clock_us() + 10000000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-controlctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ControlCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ControlCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    sim: &amp;amp;amp;Sim,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim controller scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects, and associated script stuct objects.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB): &amp;amp;amp;Script&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-eventctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type EventCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct EventCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim event handler scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    schedule_station_event: std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestationevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStationEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStationEvent {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing scheduled stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-script&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Script ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Script {&lt;br /&gt;
    id: ID&amp;amp;lt;Script&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shift&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Shift ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Shift {&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::kind(self: &amp;amp;amp;Signal): mut SignalKind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the signal kind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStationEvent&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStationEvent&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Script&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::clock_us(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current microseconds since the creation of this saved game. This is used as the timing root of the simulation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second since 1970-01-01:00:00:00.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
Probe a track position for train reservations and occupations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Seconds since 1970-01-01:00:00:00 for Monday 00:00:00 of the current week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
Advance the iterator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftallow&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftAllow ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ShiftAllow {&lt;br /&gt;
    Allow,&lt;br /&gt;
    Deny,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-shiftsetup&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ShiftSetup ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ShiftSetup {&lt;br /&gt;
    skip: bool,&lt;br /&gt;
    match_pos: bool,&lt;br /&gt;
    check_occupation: bool,&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores the context of a train shift lookup.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function wants to change the train path, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signallookaheadresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalLookaheadResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalLookaheadResult {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores extra information associated with the result of the signal lookahead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-sim&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Sim ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Sim {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of the simulation state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Sim::view&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Sim, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A proxy mutable API to the simulation engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(self: &amp;amp;amp;mut SimController, train: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=546</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=546"/>
		<updated>2025-12-01T20:22:44Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used in game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration, integer division or arbitrary setting of pointers and references, and most data exposed to scripts is read-only, strictly enforced by the language. Any expression result which could result in an out of bounds or invalid memory access must be checked for validity, and the API design together with the type system enforces it.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
pub struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;SpeedTrap,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- VisMod? 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' NAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Script&amp;lt;/code&amp;gt; (with restrictions)&lt;br /&gt;
&lt;br /&gt;
Structs extending game types for player extensions must be declared as &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt;. When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
To read struct objects from script code they must be looked up using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API. Therefore only functions provided with &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt; object (or a context object with contains &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt;) can look up these objects. But you can pass around &amp;lt;code&amp;gt;DB&amp;amp;amp;&amp;lt;/code&amp;gt; as a parameter without any lifetime restrictions, since it’s a purely read only API. This API also works for non-pub structs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= ctx.db.view&amp;amp;lt;Example&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    log(&amp;amp;quot;v = @&amp;amp;quot;, config.v);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;pub-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== pub structs ====&lt;br /&gt;
&lt;br /&gt;
As explained earlier, &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs are the user interface of your scripts. They are exposed in the UI as input forms, and their &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;s can give some control over this rendering. Conceptually they are owned by the player of the game as part of the game object database, by attaching them to a game model object in the database, not the script. Scripts do not have any capability to create, edit or delete objects of &amp;lt;code&amp;gt;pub struct&amp;lt;/code&amp;gt;s. It is always the player who decides when to create a new object of these structs by interacting in the UI. Scripts can then read, and only read, the content of these objects, by using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API presented earlier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs have a very powerful capability: they have limited support for forward schema evolution. This means that the script developer can add to, and reorder, fields in &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, and the game runtime will be able keep the contents of the other fields intact. This is very important to respect the input data by the player. If you rename &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs or their fields, or change their types, the player input data will be lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;non-pub-or-private-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Non-pub (or private) structs ====&lt;br /&gt;
&lt;br /&gt;
Non-&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, also called private structs, are conceptually owned by the script as a part of the simulation, not the player. Their contents are assumed to be a black box by the rest of the game. Scripts are allowed to create and modify objects of these structs during their execution, which are automatically deleted at the end of the simulation frame. It is also possible to attach these structs to existing game model objects to extend their lifetime beyond the current frame. In this case their lifetime becomes the same as the game object, and they can be retrieved in later frames for reading, deleted or overwritten as desired.&lt;br /&gt;
&lt;br /&gt;
Private structs ''do not support schema evolution''. Changing field types, field names, reordering of fields, even just adding new fields at the end, will always result in losing all existing attached objects of the given struct. Some operations like resetting the simulation will also erase attached objects, because they are considered simulation state, not player created objects.&lt;br /&gt;
&lt;br /&gt;
Private structs support dynamic memory allocation. All private struct definitions automatically create a &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; method for the struct:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct PrivData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let ro &amp;amp;amp;= ctx.db.view&amp;amp;lt;PrivData&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    let rw &amp;amp;amp;mut= PrivData::clone(ro);&lt;br /&gt;
    rw.v = 100;&lt;br /&gt;
    let empty &amp;amp;amp;mut= PrivData::new();&lt;br /&gt;
    empty.v = 200;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The objects allocated by &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; are always deleted at the end of the current simulation frame. Their lifetime can be extended beyond the current frame by attaching them to a game object, like &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, so their lifetime becomes the same as the attached object. The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API has methods for attaching and erasing these object.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;host-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Host structs ====&lt;br /&gt;
&lt;br /&gt;
Many of the exposed game APIs are also based around structs. These structs do not follow any of the previous rules. Some have special capabilities, for example simple structs like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt; are ''value objects'': they can be copied and passed around like any &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; would. Some others are strictly locked down and serve as very little beyond a way to keep a pointer safe. In general, when working with game API structs, assume they are what would be called ''move only'' in C++. And NimbyScript has no move operator or semantics, so in essence assume they are immutable, immobile references, except when documented otherwise (like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As an aside, all script declared &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; or not) are also always ''move only'', and always “owned” by some external entity. This is why the APIs for their manipulation are always based on pointers and references, even for private structs. It is not possible to create plain, stack allocated values of script structs, or to use them as fields in structs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version:&lt;br /&gt;
&lt;br /&gt;
* Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
* Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums)&lt;br /&gt;
* For pub structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* For private structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In pub structs these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- 'let' BindBody 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- 'let' BindBody ';'&lt;br /&gt;
BindBody    &amp;amp;lt;- NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' 'let' BindBody BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- ColonNAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere, pointer types cannot be deferenced, therefore cannot be used in dot expressions. But built-in functions &amp;lt;code&amp;gt;is_null(v): bool&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;is_valid(v): bool&amp;lt;/code&amp;gt; are usable with any pointer type and value.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;extensions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Extensions =&lt;br /&gt;
&lt;br /&gt;
Extending game database struct data with &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt; can also be used to extend the game code. The mechanism to do so is to first declare a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;ing a game database object (with or without fields). Then create a specifically named and parametrized function which will be called by the game under certain situations, for certain kinds of objects.&lt;br /&gt;
&lt;br /&gt;
All extension functions take a &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter which is a reference to the struct which it is method of, called &amp;lt;code&amp;gt;Example&amp;lt;/code&amp;gt; in the following sections. Replace it with your struct name. The rest of the parameters are fixed and must be reproduced exactly as-is.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
Event functions are called as part of the core simulation engine. They are meant to be focused in features and quick to execute. These functions might be called thousands of times per simulation frame, including multiple redundant times. Their capability to change the simulation behavior is usually very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_check&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_check ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails, or if another script call returns &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt;. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_lookahead&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_lookahead ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_lookahead(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    train_distance: f64,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalLookaheadResult&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; function at regular intervals for each signal 15km ahead of the train path. It is called for all signals, until one of these conditions hold: - One of the signals path checks as &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; - Another train is found - The train stop is found - 15km have been checked&lt;br /&gt;
&lt;br /&gt;
For both &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; signals, your &amp;lt;code&amp;gt;event_signal_lookahead&amp;lt;/code&amp;gt; will be called, and you can check the path find result in &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;, and the distance from the train in &amp;lt;code&amp;gt;train_distance&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; allows to set a maximum speed for the train, which goes into effect immediately. This works from any distance and past any amount of signals between the train and the caller signal. If multiple signals in the lookahead path return a &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt;, the slowest speed is picked. If no &amp;lt;code&amp;gt;max_speed&amp;lt;/code&amp;gt; is set, or it is 0, the result is ignored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;result.max_speed&amp;lt;/code&amp;gt; default value is 0, which is considered invalid and will be ignored. To stop the train at the signal implement &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_change_path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_change_path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_change_path(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The current path check result of this signal for the passed train is passed as &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;. This already includes any results from &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_pass_by&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_pass_by ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_pass_by(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; function on the exact simulation frame a train passes by the exact point of the signal on the track.&lt;br /&gt;
&lt;br /&gt;
This function has no return result. Instead, since it has a predictably low call rate compared to the other events, it is the only event function with access to the powerful &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_marker_reserved&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_marker_reserved ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given marker signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; any time the reservation check algorithm is tracing a path which goes over the marker signal, on any direction, giving it the chance to report an arbitrary train as the reserver of that point on the track.&lt;br /&gt;
&lt;br /&gt;
This signal has a potential huge call rate, and for this reason it is given very little access to the APIs. The intention is that all the state required by this signal is calculated somewhere else and attached to the signal as a private struct object, or to some object reachable from it. Don’t worry about filtering for the “same train” cases, this is automatically done.&lt;br /&gt;
&lt;br /&gt;
If no reservation is desired, use the &amp;lt;code&amp;gt;empty&amp;lt;/code&amp;gt; global method available in all &amp;lt;code&amp;gt;ID&amp;amp;lt;Class&amp;amp;gt;&amp;lt;/code&amp;gt; types: &amp;lt;code&amp;gt;return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal {}&lt;br /&gt;
struct Owner {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; {&lt;br /&gt;
    // some other, more full featured script function has attached Owner to this signal,&lt;br /&gt;
    // or not, so we need to check first&lt;br /&gt;
    if let owner &amp;amp;amp;= db.view&amp;amp;lt;Owner&amp;amp;gt;(signal) {&lt;br /&gt;
        if is_valid(db.view(owner.train_id)) {&lt;br /&gt;
            return owner.train_id;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_texture_state&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_texture_state ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_texture_state(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): i64 { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment, when the game UI needs to query what is the current signal texture state index, it will call your &amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt;, with some potential caching to keep the call rate lower. In any case the call rate of this function is potentially very large when the user zooms out the map, so make sure to keep its code as efficient as possible. For this same reason it is given very little access to the APIs.&lt;br /&gt;
&lt;br /&gt;
The return value indicates which signal texture state is to be used. If it’s -1 or lower, the default algorithm will be used to select the texture index. If it’s 0 or larger, it will select the texture in the same order as the &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; lines in the &amp;lt;code&amp;gt;SignalTextures&amp;lt;/code&amp;gt;. Larger values than the number of states will be clamped to the last state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;controllers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Controllers ==&lt;br /&gt;
&lt;br /&gt;
Controller functions are called at a low frame rate compared to the overall simulation, with an (unchangeable) rate of once in 6 sim-seconds. In exchange they can invoke powerful ''commands'' as their execution result, and do not need any specific event or trigger to run, other than their enforced timer&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-control_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train control_train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct HateDepots extend Train {}&lt;br /&gt;
pub fn HateDepots::control_train(&lt;br /&gt;
    self: &amp;amp;amp;HateDepots,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    // train is already removed from the tracks, don't interfere with potential attempts at shift assignation&lt;br /&gt;
    if is_null(motion.presence.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is running a schedule, don't interfere&lt;br /&gt;
    if is_valid(motion.schedule_dispatch.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is present, but it is not running a schedule, so despawn it&lt;br /&gt;
    sc.queue_train_intervention(train);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The train motion engine will call train controllers after the entire simulation for a given frame is done, and all threads are finished. Command execution will only happen after all train controllers for a given frame are done. In other words, train controllers are given a consistent, read-only snapshot of the train sim, and queue up work to be executed by the sim. They never directly change the sim in any way, allowing train controller execution to be fully parallel.&lt;br /&gt;
&lt;br /&gt;
After all controllers are run, and all their non-task commands are executed, tasks are executed. Read more about tasks later on. Any tasks with a deadline which expired in this frame a run at this time too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontroller-command-queue&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== SimController command queue ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; object implements an API to control the simulation, including modification of some parameters and behaviors. It is also responsible for attaching and erasing private struct data from game objects, on behalf of scripts. The execution of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; is based on a command queue. Every call queues a command and returns immediately to the script code, without making any changes to the game state. Therefore the game state never changes while the script code is running.&lt;br /&gt;
&lt;br /&gt;
For control scripts, commands are executed asynchronously, there is no guaranteed order of execution! You must prepare your code and data for this design. For tasks scripts commands are executed in order and in isolation. You can queue up tasks from control scripts when you need to guarantee data consistency beyond “pick a random winner”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_intervention&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_intervention ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks, releases its schedule shift (if any), and deletes and refunds its pax (if any). No other cost other than pax refunds is issued. This function can be used as a general “despawn the train” feature, not just for exceptional circumstances.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_warp&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_warp ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks and repositions it at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, re-pathing it to its currently scheduled destination (if any), and setting its speed to 0. This is basically a train wormhole. The train keeps its shift and pax, if any.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_drive_to&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_drive_to ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Re-paths the train path to end at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, without any changes to its shift or pax (if any). It is possible for any future &amp;lt;code&amp;gt;queue_train_drive_to&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; to reset this path at any point, losing the destination. “Queue” here is used as part of the SimController API semantics, it does not mean the train keeps a queue of positions to reach. If the path is not interrupted and the train reaches &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; it will re-path itself towards its current scheduled stop, if it has any, or brake to a stop if unassigned. If &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; was also in the stop area set for its current scheduled stop it will also brake to stop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_attach&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_attach ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the attachment of the &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) to the &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt;, which must be of one of the following types: &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attached objects can be accessed with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt; at some point in the future. If called from a controller function, the attached object will be accessible after all controller functions are done for a given frame. If called from a task, he attached object will be accessible immediately after the task returns, and before any other task is executed. In other words, tasks are transaction-like, in the sense they view an immutable snapshot of the game state, and any changes they queue are executed before any other task, and then visible from these other tasks.&lt;br /&gt;
&lt;br /&gt;
Attaching an object of a given private struct type when it already exists attached to a &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt; will overwrite it. This is how private data is updated from scripting: by using &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; to copy any existing data, modifying the copy, then calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; to replace the existing data. Therefore it is a good idea to keep your private structs small. Only one instance of a given private struct type can be attached to any particular model object, but you can attach as many different private struct types as you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_erase&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_erase ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the erasure of &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt;, which must obtained using with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt;. Trying to erase temporary objects (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) is ignored. The execution of the queued erase commands is analog to the &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; case. In particular a sequences of attach and erase queued from controllers will produce undefined results (impossible to predict which attach and/or erase wins). For example multiple attach from a controller for the same model_obj and private struct type will implicitly pick a singular “winner” attach, but the script does not have any control over which one. Sequences of attach and erase queued from tasks are strictly ordered and isolated, so they produce consistent results, in the same order they were queued in the task script, without any concurrent changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task-and-simcontrollerqueue_task_at&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task and SimController::queue_task_at ===&lt;br /&gt;
&lt;br /&gt;
These functions are documented in the next section.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
Tasks are a very special kind of command which allows scripts to dynamically queue “future work”. Scripts with access to &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; can call this function to queue up a task for future script execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; must be of a private struct type which implements &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example { ... }&lt;br /&gt;
pub fn Example::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
For example, a train controller script could decide it needs to delay some decision into a task for data consistency reasons (other controllers are running at the same time), and delegate into a task rather than directly calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ControlTrain extends Train { ... }&lt;br /&gt;
pub fn ControlTrain::control_train(&lt;br /&gt;
    self: &amp;amp;amp;ControlTrain,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    task.train_id = train.id;&lt;br /&gt;
    task.v = some_data_from_somewhere;&lt;br /&gt;
    task.prio = 42; // or something smarter, like from ControlTrain, other objects, etc.&lt;br /&gt;
    sc.queue_task(task);&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
struct Task {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
struct SomeData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
pub fn Task::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    let train &amp;amp;amp;= ctx.db.view(self.train_id) else { return; }&lt;br /&gt;
    if let existing &amp;amp;amp;= ctx.db.view&amp;amp;lt;SomeData&amp;amp;gt;(train) {&lt;br /&gt;
        if existing.prio &amp;amp;gt;= self.prio {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    let data = SomeData::new();&lt;br /&gt;
    data.v = self.v;&lt;br /&gt;
    data.prio = self.prio;&lt;br /&gt;
    sc.queue_attach(train, data);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the previous example, maybe &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; will be called multiple times because multiple &amp;lt;code&amp;gt;ControlTrain::control_train()&amp;lt;/code&amp;gt; instances queued objects of &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;, but each execution will be single threaded, and all its queued &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; commands will be executed just after the call is done and before any other &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; call (for &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; or any other struct type), therefore the algorithm to pick a winner based on an explicit priority works.&lt;br /&gt;
&lt;br /&gt;
As mentioned, task execution is single threaded. The game does not feature a real concurrent database, instead all concurrent access is bespoke and very carefully designed to avoid deadlocks and inconsistencies (this is much faster than a general purpose concurrent database). Scripts also run in this parallel system, but their access to the game state is carefully restricted as explained earlier. But in the end, scripts also need to modify data, and do so in a consistent way. Tasks solve this issue, but do so in the most pessimistic possible way, by being single threaded. Therefore script developers should use them in moderation. Consider the “random winner” semantics of control script queuing first, which are completely free performance wise, before deciding you need a task. It is often the case a concurrent problem reduces to “pick 0 or 1 winners, any winner, but never 2 or more” and the default queue semantics already provide that guarantee for attaching a specific model/private pair.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; is provided with &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt;, therefore it can queue tasks itself. But unlike controller queuing tasks, which are guaranteed to run on the same frame, tasks queued from tasks are guaranteed to ''not'' run on the same frame, on purpose. They are deliberately stored away and forced a delay of 6 sim-seconds. This is to avoid misuse of tasks, and infinite looping.&lt;br /&gt;
&lt;br /&gt;
This behavior might even be desirable in certain scripts, for example if you are developing some stateful signal system and you need some kind of “cleanup” task that makes sure some signal being owned by some train is still the focus of said train. You can deliberately queue tasks for future simulation frames with &amp;lt;code&amp;gt;queue_task_at&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;deadline&amp;lt;/code&amp;gt; is expressed as microseconds since the start of the current save world. You can obtain the current simulation frame &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; value with &amp;lt;code&amp;gt;Extrapolator::clock_us()&amp;lt;/code&amp;gt;, like in this example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;    // schedule task to run 10 sim-s from now&lt;br /&gt;
    sc.queue_task_at(task, ctx.extrapolator.clock_us() + 10000000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-controlctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ControlCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ControlCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    sim: &amp;amp;amp;Sim,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim controller scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects, and associated script stuct objects.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB): &amp;amp;amp;Script&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-eventctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type EventCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct EventCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim event handler scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    schedule_station_event: std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestationevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStationEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStationEvent {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing scheduled stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-script&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Script ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Script {&lt;br /&gt;
    id: ID&amp;amp;lt;Script&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::kind(self: &amp;amp;amp;Signal): mut SignalKind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the signal kind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStationEvent&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStationEvent&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Script&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::clock_us(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current microseconds since the creation of this saved game. This is used as the timing root of the simulation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second since 1970-01-01:00:00:00.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
Probe a track position for train reservations and occupations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Seconds since 1970-01-01:00:00:00 for Monday 00:00:00 of the current week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
Advance the iterator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function wants to change the train path, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signallookaheadresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalLookaheadResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalLookaheadResult {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores extra information associated with the result of the signal lookahead.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-sim&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Sim ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Sim {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of the simulation state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Sim::view&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Sim, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A proxy mutable API to the simulation engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(self: &amp;amp;amp;mut SimController, train: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=544</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=544"/>
		<updated>2025-11-29T15:52:06Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used in game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration, integer division or arbitrary setting of pointers and references, and most data exposed to scripts is read-only, strictly enforced by the language. Any expression result which could result in an out of bounds or invalid memory access must be checked for validity, and the API design together with the type system enforces it.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
pub struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;SpeedTrap,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalCheckResult&lt;br /&gt;
): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- VisMod? 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' NAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Script&amp;lt;/code&amp;gt; (with restrictions)&lt;br /&gt;
&lt;br /&gt;
Structs extending game types for player extensions must be declared as &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt;. When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
To read struct objects from script code they must be looked up using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API. Therefore only functions provided with &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt; object (or a context object with contains &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt;) can look up these objects. But you can pass around &amp;lt;code&amp;gt;DB&amp;amp;amp;&amp;lt;/code&amp;gt; as a parameter without any lifetime restrictions, since it’s a purely read only API. This API also works for non-pub structs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= ctx.db.view&amp;amp;lt;Example&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    log(&amp;amp;quot;v = @&amp;amp;quot;, config.v);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;pub-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== pub structs ====&lt;br /&gt;
&lt;br /&gt;
As explained earlier, &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs are the user interface of your scripts. They are exposed in the UI as input forms, and their &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;s can give some control over this rendering. Conceptually they are owned by the player of the game as part of the game object database, by attaching them to a game model object in the database, not the script. Scripts do not have any capability to create, edit or delete objects of &amp;lt;code&amp;gt;pub struct&amp;lt;/code&amp;gt;s. It is always the player who decides when to create a new object of these structs by interacting in the UI. Scripts can then read, and only read, the content of these objects, by using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API presented earlier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs have a very powerful capability: they have limited support for forward schema evolution. This means that the script developer can add to, and reorder, fields in &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, and the game runtime will be able keep the contents of the other fields intact. This is very important to respect the input data by the player. If you rename &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs or their fields, or change their types, the player input data will be lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;non-pub-or-private-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Non-pub (or private) structs ====&lt;br /&gt;
&lt;br /&gt;
Non-&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, also called private structs, are conceptually owned by the script as a part of the simulation, not the player. Their contents are assumed to be a black box by the rest of the game. Scripts are allowed to create and modify objects of these structs during their execution, which are automatically deleted at the end of the simulation frame. It is also possible to attach these structs to existing game model objects to extend their lifetime beyond the current frame. In this case their lifetime becomes the same as the game object, and they can be retrieved in later frames for reading, deleted or overwritten as desired.&lt;br /&gt;
&lt;br /&gt;
Private structs ''do not support schema evolution''. Changing field types, field names, reordering of fields, even just adding new fields at the end, will always result in losing all existing attached objects of the given struct. Some operations like resetting the simulation will also erase attached objects, because they are considered simulation state, not player created objects.&lt;br /&gt;
&lt;br /&gt;
Private structs support dynamic memory allocation. All private struct definitions automatically create a &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; method for the struct:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct PrivData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let ro &amp;amp;amp;= ctx.db.view&amp;amp;lt;PrivData&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    let rw &amp;amp;amp;mut= PrivData::clone(ro);&lt;br /&gt;
    rw.v = 100;&lt;br /&gt;
    let empty &amp;amp;amp;mut= PrivData::new();&lt;br /&gt;
    empty.v = 200;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The objects allocated by &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; are always deleted at the end of the current simulation frame. Their lifetime can be extended beyond the current frame by attaching them to a game object, like &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, so their lifetime becomes the same as the attached object. The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API has methods for attaching and erasing these object.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;host-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Host structs ====&lt;br /&gt;
&lt;br /&gt;
Many of the exposed game APIs are also based around structs. These structs do not follow any of the previous rules. Some have special capabilities, for example simple structs like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt; are ''value objects'': they can be copied and passed around like any &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; would. Some others are strictly locked down and serve as very little beyond a way to keep a pointer safe. In general, when working with game API structs, assume they are what would be called ''move only'' in C++. And NimbyScript has no move operator or semantics, so in essence assume they are immutable, immobile references, except when documented otherwise (like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As an aside, all script declared &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; or not) are also always ''move only'', and always “owned” by some external entity. This is why the APIs for their manipulation are always based on pointers and references, even for private structs. It is not possible to create plain, stack allocated values of script structs, or to use them as fields in structs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version:&lt;br /&gt;
&lt;br /&gt;
* Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
* Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums)&lt;br /&gt;
* For pub structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* For private structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In pub structs these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- 'let' BindBody 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- 'let' BindBody ';'&lt;br /&gt;
BindBody    &amp;amp;lt;- NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' 'let' BindBody BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- ColonNAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere, pointer types cannot be deferenced, therefore cannot be used in dot expressions. But built-in functions &amp;lt;code&amp;gt;is_null(v): bool&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;is_valid(v): bool&amp;lt;/code&amp;gt; are usable with any pointer type and value.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;extensions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Extensions =&lt;br /&gt;
&lt;br /&gt;
Extending game database struct data with &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt; can also be used to extend the game code. The mechanism to do so is to first declare a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;ing a game database object (with or without fields). Then create a specifically named and parametrized function which will be called by the game under certain situations, for certain kinds of objects.&lt;br /&gt;
&lt;br /&gt;
All extension functions take a &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter which is a reference to the struct which it is method of, called &amp;lt;code&amp;gt;Example&amp;lt;/code&amp;gt; in the following sections. Replace it with your struct name. The rest of the parameters are fixed and must be reproduced exactly as-is.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
Event functions are called as part of the core simulation engine. They are meant to be focused in features and quick to execute. These functions might be called thousands of times per simulation frame, including multiple redundant times. Their capability to change the simulation behavior is usually very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_check&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_check ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalCheckResult&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;PassAtSpeed&amp;lt;/code&amp;gt; is for all path checking and reservation purposes equivalent to &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt;, but it will create a max speed (set in &amp;lt;code&amp;gt;result.speed&amp;lt;/code&amp;gt;) restriction obstacle at the signal point when &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; is being called while the train is at braking distance from the signal, before it passes-by it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_change_path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_change_path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_change_path(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The current path check result of this signal for the passed train is passed as &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;. This already includes any results from &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_pass_by&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_pass_by ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_pass_by(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; function on the exact simulation frame a train passes by the exact point of the signal on the track.&lt;br /&gt;
&lt;br /&gt;
This function has no return result. Instead, since it has a predictably low call rate compared to the other events, it is the only event function with access to the powerful &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_marker_reserved&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_marker_reserved ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given marker signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; any time the reservation check algorithm is tracing a path which goes over the marker signal, on any direction, giving it the chance to report an arbitrary train as the reserver of that point on the track.&lt;br /&gt;
&lt;br /&gt;
This signal has a potential huge call rate, and for this reason it is given very little access to the APIs. The intention is that all the state required by this signal is calculated somewhere else and attached to the signal as a private struct object, or to some object reachable from it. Don’t worry about filtering for the “same train” cases, this is automatically done.&lt;br /&gt;
&lt;br /&gt;
If no reservation is desired, use the &amp;lt;code&amp;gt;empty&amp;lt;/code&amp;gt; global method available in all &amp;lt;code&amp;gt;ID&amp;amp;lt;Class&amp;amp;gt;&amp;lt;/code&amp;gt; types: &amp;lt;code&amp;gt;return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal {}&lt;br /&gt;
struct Owner {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; {&lt;br /&gt;
    // some other, more full featured script function has attached Owner to this signal,&lt;br /&gt;
    // or not, so we need to check first&lt;br /&gt;
    if let owner &amp;amp;amp;= db.view&amp;amp;lt;Owner&amp;amp;gt;(signal) {&lt;br /&gt;
        if is_valid(db.view(owner.train_id)) {&lt;br /&gt;
            return owner.train_id;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_texture_state&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_texture_state ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_texture_state(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): i64 { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment, when the game UI needs to query what is the current signal texture state index, it will call your &amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt;, with some potential caching to keep the call rate lower. In any case the call rate of this function is potentially very large when the user zooms out the map, so make sure to keep its code as efficient as possible. For this same reason it is given very little access to the APIs.&lt;br /&gt;
&lt;br /&gt;
The return value indicates which signal texture state is to be used. If it’s -1 or lower, the default algorithm will be used to select the texture index. If it’s 0 or larger, it will select the texture in the same order as the &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; lines in the &amp;lt;code&amp;gt;SignalTextures&amp;lt;/code&amp;gt;. Larger values than the number of states will be clamped to the last state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;controllers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Controllers ==&lt;br /&gt;
&lt;br /&gt;
Controller functions are called at a low frame rate compared to the overall simulation, with an (unchangeable) rate of once in 6 sim-seconds. In exchange they can invoke powerful ''commands'' as their execution result, and do not need any specific event or trigger to run, other than their enforced timer&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-control_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train control_train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct HateDepots extend Train {}&lt;br /&gt;
pub fn HateDepots::control_train(&lt;br /&gt;
    self: &amp;amp;amp;HateDepots,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    // train is already removed from the tracks, don't interfere with potential attempts at shift assignation&lt;br /&gt;
    if is_null(motion.presence.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is running a schedule, don't interfere&lt;br /&gt;
    if is_valid(motion.schedule_dispatch.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is present, but it is not running a schedule, so despawn it&lt;br /&gt;
    sc.queue_train_intervention(train);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The train motion engine will call train controllers after the entire simulation for a given frame is done, and all threads are finished. Command execution will only happen after all train controllers for a given frame are done. In other words, train controllers are given a consistent, read-only snapshot of the train sim, and queue up work to be executed by the sim. They never directly change the sim in any way, allowing train controller execution to be fully parallel.&lt;br /&gt;
&lt;br /&gt;
After all controllers are run, and all their non-task commands are executed, tasks are executed. Read more about tasks later on. Any tasks with a deadline which expired in this frame a run at this time too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontroller-command-queue&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== SimController command queue ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; object implements an API to control the simulation, including modification of some parameters and behaviors. It is also responsible for attaching and erasing private struct data from game objects, on behalf of scripts. The execution of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; is based on a command queue. Every call queues a command and returns immediately to the script code, without making any changes to the game state. Therefore the game state never changes while the script code is running.&lt;br /&gt;
&lt;br /&gt;
For control scripts, commands are executed asynchronously, there is no guaranteed order of execution! You must prepare your code and data for this design. For tasks scripts commands are executed in order and in isolation. You can queue up tasks from control scripts when you need to guarantee data consistency beyond “pick a random winner”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_intervention&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_intervention ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks, releases its schedule shift (if any), and deletes and refunds its pax (if any). No other cost other than pax refunds is issued. This function can be used as a general “despawn the train” feature, not just for exceptional circumstances.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_warp&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_warp ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks and repositions it at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, re-pathing it to its currently scheduled destination (if any), and setting its speed to 0. This is basically a train wormhole. The train keeps its shift and pax, if any.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_drive_to&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_drive_to ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Re-paths the train path to end at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, without any changes to its shift or pax (if any). It is possible for any future &amp;lt;code&amp;gt;queue_train_drive_to&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; to reset this path at any point, losing the destination. “Queue” here is used as part of the SimController API semantics, it does not mean the train keeps a queue of positions to reach. If the path is not interrupted and the train reaches &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; it will re-path itself towards its current scheduled stop, if it has any, or brake to a stop if unassigned. If &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; was also in the stop area set for its current scheduled stop it will also brake to stop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_attach&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_attach ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the attachment of the &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) to the &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt;, which must be of one of the following types: &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attached objects can be accessed with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt; at some point in the future. If called from a controller function, the attached object will be accessible after all controller functions are done for a given frame. If called from a task, he attached object will be accessible immediately after the task returns, and before any other task is executed. In other words, tasks are transaction-like, in the sense they view an immutable snapshot of the game state, and any changes they queue are executed before any other task, and then visible from these other tasks.&lt;br /&gt;
&lt;br /&gt;
Attaching an object of a given private struct type when it already exists attached to a &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt; will overwrite it. This is how private data is updated from scripting: by using &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; to copy any existing data, modifying the copy, then calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; to replace the existing data. Therefore it is a good idea to keep your private structs small. Only one instance of a given private struct type can be attached to any particular model object, but you can attach as many different private struct types as you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_erase&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_erase ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the erasure of &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt;, which must obtained using with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt;. Trying to erase temporary objects (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) is ignored. The execution of the queued erase commands is analog to the &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; case. In particular a sequences of attach and erase queued from controllers will produce undefined results (impossible to predict which attach and/or erase wins). For example multiple attach from a controller for the same model_obj and private struct type will implicitly pick a singular “winner” attach, but the script does not have any control over which one. Sequences of attach and erase queued from tasks are strictly ordered and isolated, so they produce consistent results, in the same order they were queued in the task script, without any concurrent changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task-and-simcontrollerqueue_task_at&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task and SimController::queue_task_at ===&lt;br /&gt;
&lt;br /&gt;
These functions are documented in the next section.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
Tasks are a very special kind of command which allows scripts to dynamically queue “future work”. Scripts with access to &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; can call this function to queue up a task for future script execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; must be of a private struct type which implements &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example { ... }&lt;br /&gt;
pub fn Example::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
For example, a train controller script could decide it needs to delay some decision into a task for data consistency reasons (other controllers are running at the same time), and delegate into a task rather than directly calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ControlTrain extends Train { ... }&lt;br /&gt;
pub fn ControlTrain::control_train(&lt;br /&gt;
    self: &amp;amp;amp;ControlTrain,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    task.train_id = train.id;&lt;br /&gt;
    task.v = some_data_from_somewhere;&lt;br /&gt;
    task.prio = 42; // or something smarter, like from ControlTrain, other objects, etc.&lt;br /&gt;
    sc.queue_task(task);&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
struct Task {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
struct SomeData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
pub fn Task::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    let train &amp;amp;amp;= ctx.db.view(self.train_id) else { return; }&lt;br /&gt;
    if let existing &amp;amp;amp;= ctx.db.view&amp;amp;lt;SomeData&amp;amp;gt;(train) {&lt;br /&gt;
        if existing.prio &amp;amp;gt;= self.prio {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    let data = SomeData::new();&lt;br /&gt;
    data.v = self.v;&lt;br /&gt;
    data.prio = self.prio;&lt;br /&gt;
    sc.queue_attach(train, data);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the previous example, maybe &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; will be called multiple times because multiple &amp;lt;code&amp;gt;ControlTrain::control_train()&amp;lt;/code&amp;gt; instances queued objects of &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;, but each execution will be single threaded, and all its queued &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; commands will be executed just after the call is done and before any other &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; call (for &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; or any other struct type), therefore the algorithm to pick a winner based on an explicit priority works.&lt;br /&gt;
&lt;br /&gt;
As mentioned, task execution is single threaded. The game does not feature a real concurrent database, instead all concurrent access is bespoke and very carefully designed to avoid deadlocks and inconsistencies (this is much faster than a general purpose concurrent database). Scripts also run in this parallel system, but their access to the game state is carefully restricted as explained earlier. But in the end, scripts also need to modify data, and do so in a consistent way. Tasks solve this issue, but do so in the most pessimistic possible way, by being single threaded. Therefore script developers should use them in moderation. Consider the “random winner” semantics of control script queuing first, which are completely free performance wise, before deciding you need a task. It is often the case a concurrent problem reduces to “pick 0 or 1 winners, any winner, but never 2 or more” and the default queue semantics already provide that guarantee for attaching a specific model/private pair.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; is provided with &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt;, therefore it can queue tasks itself. But unlike controller queuing tasks, which are guaranteed to run on the same frame, tasks queued from tasks are guaranteed to ''not'' run on the same frame, on purpose. They are deliberately stored away and forced a delay of 6 sim-seconds. This is to avoid misuse of tasks, and infinite looping.&lt;br /&gt;
&lt;br /&gt;
This behavior might even be desirable in certain scripts, for example if you are developing some stateful signal system and you need some kind of “cleanup” task that makes sure some signal being owned by some train is still the focus of said train. You can deliberately queue tasks for future simulation frames with &amp;lt;code&amp;gt;queue_task_at&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;deadline&amp;lt;/code&amp;gt; is expressed as microseconds since the start of the current save world. You can obtain the current simulation frame &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; value with &amp;lt;code&amp;gt;Extrapolator::clock_us()&amp;lt;/code&amp;gt;, like in this example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;    // schedule task to run 10 sim-s from now&lt;br /&gt;
    sc.queue_task_at(task, ctx.extrapolator.clock_us() + 10000000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-controlctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ControlCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ControlCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    sim: &amp;amp;amp;Sim,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim controller scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects, and associated script stuct objects.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB): &amp;amp;amp;Script&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-eventctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type EventCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct EventCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim event handler scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    schedule_station_event: std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestationevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStationEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStationEvent {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing scheduled stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-script&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Script ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Script {&lt;br /&gt;
    id: ID&amp;amp;lt;Script&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::kind(self: &amp;amp;amp;Signal): mut SignalKind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the signal kind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStationEvent&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStationEvent&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Script&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::clock_us(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current microseconds since the creation of this saved game. This is used as the timing root of the simulation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second since 1970-01-01:00:00:00.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
Probe a track position for train reservations and occupations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Seconds since 1970-01-01:00:00:00 for Monday 00:00:00 of the current week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
Advance the iterator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function wants to change the train path, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    PassAtSpeed,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheckresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheckResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalCheckResult {&lt;br /&gt;
    speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores extra information associated with the result of the signal check. The ‘speed’ parameter is used with the SignalCheck::PassAtSpeed return, ignored otherwise.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-sim&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Sim ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Sim {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of the simulation state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Sim::view&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Sim, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A proxy mutable API to the simulation engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(self: &amp;amp;amp;mut SimController, train: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=543</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=543"/>
		<updated>2025-11-29T15:49:55Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used in game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration, integer division or arbitrary setting of pointers and references, and most data exposed to scripts is read-only, strictly enforced by the language. Any expression result which could result in an out of bounds or invalid memory access must be checked for validity, and the API design together with the type system enforces it.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
pub struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;ProbeCheck,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalCheckResult&lt;br /&gt;
): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- VisMod? 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' NAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Script&amp;lt;/code&amp;gt; (with restrictions)&lt;br /&gt;
&lt;br /&gt;
Structs extending game types for player extensions must be declared as &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt;. When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
To read struct objects from script code they must be looked up using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API. Therefore only functions provided with &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt; object (or a context object with contains &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt;) can look up these objects. But you can pass around &amp;lt;code&amp;gt;DB&amp;amp;amp;&amp;lt;/code&amp;gt; as a parameter without any lifetime restrictions, since it’s a purely read only API. This API also works for non-pub structs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= ctx.db.view&amp;amp;lt;Example&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    log(&amp;amp;quot;v = @&amp;amp;quot;, config.v);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;pub-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== pub structs ====&lt;br /&gt;
&lt;br /&gt;
As explained earlier, &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs are the user interface of your scripts. They are exposed in the UI as input forms, and their &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;s can give some control over this rendering. Conceptually they are owned by the player of the game as part of the game object database, by attaching them to a game model object in the database, not the script. Scripts do not have any capability to create, edit or delete objects of &amp;lt;code&amp;gt;pub struct&amp;lt;/code&amp;gt;s. It is always the player who decides when to create a new object of these structs by interacting in the UI. Scripts can then read, and only read, the content of these objects, by using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API presented earlier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs have a very powerful capability: they have limited support for forward schema evolution. This means that the script developer can add to, and reorder, fields in &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, and the game runtime will be able keep the contents of the other fields intact. This is very important to respect the input data by the player. If you rename &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs or their fields, or change their types, the player input data will be lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;non-pub-or-private-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Non-pub (or private) structs ====&lt;br /&gt;
&lt;br /&gt;
Non-&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, also called private structs, are conceptually owned by the script as a part of the simulation, not the player. Their contents are assumed to be a black box by the rest of the game. Scripts are allowed to create and modify objects of these structs during their execution, which are automatically deleted at the end of the simulation frame. It is also possible to attach these structs to existing game model objects to extend their lifetime beyond the current frame. In this case their lifetime becomes the same as the game object, and they can be retrieved in later frames for reading, deleted or overwritten as desired.&lt;br /&gt;
&lt;br /&gt;
Private structs ''do not support schema evolution''. Changing field types, field names, reordering of fields, even just adding new fields at the end, will always result in losing all existing attached objects of the given struct. Some operations like resetting the simulation will also erase attached objects, because they are considered simulation state, not player created objects.&lt;br /&gt;
&lt;br /&gt;
Private structs support dynamic memory allocation. All private struct definitions automatically create a &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; method for the struct:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct PrivData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let ro &amp;amp;amp;= ctx.db.view&amp;amp;lt;PrivData&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    let rw &amp;amp;amp;mut= PrivData::clone(ro);&lt;br /&gt;
    rw.v = 100;&lt;br /&gt;
    let empty &amp;amp;amp;mut= PrivData::new();&lt;br /&gt;
    empty.v = 200;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The objects allocated by &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; are always deleted at the end of the current simulation frame. Their lifetime can be extended beyond the current frame by attaching them to a game object, like &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, so their lifetime becomes the same as the attached object. The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API has methods for attaching and erasing these object.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;host-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Host structs ====&lt;br /&gt;
&lt;br /&gt;
Many of the exposed game APIs are also based around structs. These structs do not follow any of the previous rules. Some have special capabilities, for example simple structs like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt; are ''value objects'': they can be copied and passed around like any &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; would. Some others are strictly locked down and serve as very little beyond a way to keep a pointer safe. In general, when working with game API structs, assume they are what would be called ''move only'' in C++. And NimbyScript has no move operator or semantics, so in essence assume they are immutable, immobile references, except when documented otherwise (like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As an aside, all script declared &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; or not) are also always ''move only'', and always “owned” by some external entity. This is why the APIs for their manipulation are always based on pointers and references, even for private structs. It is not possible to create plain, stack allocated values of script structs, or to use them as fields in structs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version:&lt;br /&gt;
&lt;br /&gt;
* Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
* Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums)&lt;br /&gt;
* For pub structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* For private structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In pub structs these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- 'let' BindBody 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- 'let' BindBody ';'&lt;br /&gt;
BindBody    &amp;amp;lt;- NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' 'let' BindBody BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- ColonNAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere, pointer types cannot be deferenced, therefore cannot be used in dot expressions. But built-in functions &amp;lt;code&amp;gt;is_null(v): bool&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;is_valid(v): bool&amp;lt;/code&amp;gt; are usable with any pointer type and value.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;extensions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Extensions =&lt;br /&gt;
&lt;br /&gt;
Extending game database struct data with &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt; can also be used to extend the game code. The mechanism to do so is to first declare a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;ing a game database object (with or without fields). Then create a specifically named and parametrized function which will be called by the game under certain situations, for certain kinds of objects.&lt;br /&gt;
&lt;br /&gt;
All extension functions take a &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter which is a reference to the struct which it is method of, called &amp;lt;code&amp;gt;Example&amp;lt;/code&amp;gt; in the following sections. Replace it with your struct name. The rest of the parameters are fixed and must be reproduced exactly as-is.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
Event functions are called as part of the core simulation engine. They are meant to be focused in features and quick to execute. These functions might be called thousands of times per simulation frame, including multiple redundant times. Their capability to change the simulation behavior is usually very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_check&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_check ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalCheckResult&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;PassAtSpeed&amp;lt;/code&amp;gt; is for all path checking and reservation purposes equivalent to &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt;, but it will create a max speed (set in &amp;lt;code&amp;gt;result.speed&amp;lt;/code&amp;gt;) restriction obstacle at the signal point when &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; is being called while the train is at braking distance from the signal, before it passes-by it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_change_path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_change_path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_change_path(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The current path check result of this signal for the passed train is passed as &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;. This already includes any results from &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_pass_by&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_pass_by ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_pass_by(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; function on the exact simulation frame a train passes by the exact point of the signal on the track.&lt;br /&gt;
&lt;br /&gt;
This function has no return result. Instead, since it has a predictably low call rate compared to the other events, it is the only event function with access to the powerful &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_marker_reserved&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_marker_reserved ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given marker signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; any time the reservation check algorithm is tracing a path which goes over the marker signal, on any direction, giving it the chance to report an arbitrary train as the reserver of that point on the track.&lt;br /&gt;
&lt;br /&gt;
This signal has a potential huge call rate, and for this reason it is given very little access to the APIs. The intention is that all the state required by this signal is calculated somewhere else and attached to the signal as a private struct object, or to some object reachable from it. Don’t worry about filtering for the “same train” cases, this is automatically done.&lt;br /&gt;
&lt;br /&gt;
If no reservation is desired, use the &amp;lt;code&amp;gt;empty&amp;lt;/code&amp;gt; global method available in all &amp;lt;code&amp;gt;ID&amp;amp;lt;Class&amp;amp;gt;&amp;lt;/code&amp;gt; types: &amp;lt;code&amp;gt;return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal {}&lt;br /&gt;
struct Owner {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; {&lt;br /&gt;
    // some other, more full featured script function has attached Owner to this signal,&lt;br /&gt;
    // or not, so we need to check first&lt;br /&gt;
    if let owner &amp;amp;amp;= db.view&amp;amp;lt;Owner&amp;amp;gt;(signal) {&lt;br /&gt;
        if is_valid(db.view(owner.train_id)) {&lt;br /&gt;
            return owner.train_id;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_texture_state&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_texture_state ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_texture_state(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): i64 { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment, when the game UI needs to query what is the current signal texture state index, it will call your &amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt;, with some potential caching to keep the call rate lower. In any case the call rate of this function is potentially very large when the user zooms out the map, so make sure to keep its code as efficient as possible. For this same reason it is given very little access to the APIs.&lt;br /&gt;
&lt;br /&gt;
The return value indicates which signal texture state is to be used. If it’s -1 or lower, the default algorithm will be used to select the texture index. If it’s 0 or larger, it will select the texture in the same order as the &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; lines in the &amp;lt;code&amp;gt;SignalTextures&amp;lt;/code&amp;gt;. Larger values than the number of states will be clamped to the last state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;controllers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Controllers ==&lt;br /&gt;
&lt;br /&gt;
Controller functions are called at a low frame rate compared to the overall simulation, with an (unchangeable) rate of once in 6 sim-seconds. In exchange they can invoke powerful ''commands'' as their execution result, and do not need any specific event or trigger to run, other than their enforced timer&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-control_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train control_train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct HateDepots extend Train {}&lt;br /&gt;
pub fn HateDepots::control_train(&lt;br /&gt;
    self: &amp;amp;amp;HateDepots,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    // train is already removed from the tracks, don't interfere with potential attempts at shift assignation&lt;br /&gt;
    if is_null(motion.presence.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is running a schedule, don't interfere&lt;br /&gt;
    if is_valid(motion.schedule_dispatch.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is present, but it is not running a schedule, so despawn it&lt;br /&gt;
    sc.queue_train_intervention(train);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The train motion engine will call train controllers after the entire simulation for a given frame is done, and all threads are finished. Command execution will only happen after all train controllers for a given frame are done. In other words, train controllers are given a consistent, read-only snapshot of the train sim, and queue up work to be executed by the sim. They never directly change the sim in any way, allowing train controller execution to be fully parallel.&lt;br /&gt;
&lt;br /&gt;
After all controllers are run, and all their non-task commands are executed, tasks are executed. Read more about tasks later on. Any tasks with a deadline which expired in this frame a run at this time too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontroller-command-queue&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== SimController command queue ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; object implements an API to control the simulation, including modification of some parameters and behaviors. It is also responsible for attaching and erasing private struct data from game objects, on behalf of scripts. The execution of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; is based on a command queue. Every call queues a command and returns immediately to the script code, without making any changes to the game state. Therefore the game state never changes while the script code is running.&lt;br /&gt;
&lt;br /&gt;
For control scripts, commands are executed asynchronously, there is no guaranteed order of execution! You must prepare your code and data for this design. For tasks scripts commands are executed in order and in isolation. You can queue up tasks from control scripts when you need to guarantee data consistency beyond “pick a random winner”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_intervention&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_intervention ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks, releases its schedule shift (if any), and deletes and refunds its pax (if any). No other cost other than pax refunds is issued. This function can be used as a general “despawn the train” feature, not just for exceptional circumstances.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_warp&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_warp ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks and repositions it at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, re-pathing it to its currently scheduled destination (if any), and setting its speed to 0. This is basically a train wormhole. The train keeps its shift and pax, if any.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_drive_to&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_drive_to ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Re-paths the train path to end at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, without any changes to its shift or pax (if any). It is possible for any future &amp;lt;code&amp;gt;queue_train_drive_to&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; to reset this path at any point, losing the destination. “Queue” here is used as part of the SimController API semantics, it does not mean the train keeps a queue of positions to reach. If the path is not interrupted and the train reaches &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; it will re-path itself towards its current scheduled stop, if it has any, or brake to a stop if unassigned. If &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; was also in the stop area set for its current scheduled stop it will also brake to stop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_attach&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_attach ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the attachment of the &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) to the &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt;, which must be of one of the following types: &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attached objects can be accessed with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt; at some point in the future. If called from a controller function, the attached object will be accessible after all controller functions are done for a given frame. If called from a task, he attached object will be accessible immediately after the task returns, and before any other task is executed. In other words, tasks are transaction-like, in the sense they view an immutable snapshot of the game state, and any changes they queue are executed before any other task, and then visible from these other tasks.&lt;br /&gt;
&lt;br /&gt;
Attaching an object of a given private struct type when it already exists attached to a &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt; will overwrite it. This is how private data is updated from scripting: by using &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; to copy any existing data, modifying the copy, then calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; to replace the existing data. Therefore it is a good idea to keep your private structs small. Only one instance of a given private struct type can be attached to any particular model object, but you can attach as many different private struct types as you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_erase&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_erase ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the erasure of &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt;, which must obtained using with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt;. Trying to erase temporary objects (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) is ignored. The execution of the queued erase commands is analog to the &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; case. In particular a sequences of attach and erase queued from controllers will produce undefined results (impossible to predict which attach and/or erase wins). For example multiple attach from a controller for the same model_obj and private struct type will implicitly pick a singular “winner” attach, but the script does not have any control over which one. Sequences of attach and erase queued from tasks are strictly ordered and isolated, so they produce consistent results, in the same order they were queued in the task script, without any concurrent changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task-and-simcontrollerqueue_task_at&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task and SimController::queue_task_at ===&lt;br /&gt;
&lt;br /&gt;
These functions are documented in the next section.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
Tasks are a very special kind of command which allows scripts to dynamically queue “future work”. Scripts with access to &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; can call this function to queue up a task for future script execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; must be of a private struct type which implements &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example { ... }&lt;br /&gt;
pub fn Example::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
For example, a train controller script could decide it needs to delay some decision into a task for data consistency reasons (other controllers are running at the same time), and delegate into a task rather than directly calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ControlTrain extends Train { ... }&lt;br /&gt;
pub fn ControlTrain::control_train(&lt;br /&gt;
    self: &amp;amp;amp;ControlTrain,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    task.train_id = train.id;&lt;br /&gt;
    task.v = some_data_from_somewhere;&lt;br /&gt;
    task.prio = 42; // or something smarter, like from ControlTrain, other objects, etc.&lt;br /&gt;
    sc.queue_task(task);&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
struct Task {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
struct SomeData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
pub fn Task::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    let train &amp;amp;amp;= ctx.db.view(self.train_id) else { return; }&lt;br /&gt;
    if let existing &amp;amp;amp;= ctx.db.view&amp;amp;lt;SomeData&amp;amp;gt;(train) {&lt;br /&gt;
        if existing.prio &amp;amp;gt;= self.prio {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    let data = SomeData::new();&lt;br /&gt;
    data.v = self.v;&lt;br /&gt;
    data.prio = self.prio;&lt;br /&gt;
    sc.queue_attach(train, data);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the previous example, maybe &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; will be called multiple times because multiple &amp;lt;code&amp;gt;ControlTrain::control_train()&amp;lt;/code&amp;gt; instances queued objects of &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;, but each execution will be single threaded, and all its queued &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; commands will be executed just after the call is done and before any other &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; call (for &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; or any other struct type), therefore the algorithm to pick a winner based on an explicit priority works.&lt;br /&gt;
&lt;br /&gt;
As mentioned, task execution is single threaded. The game does not feature a real concurrent database, instead all concurrent access is bespoke and very carefully designed to avoid deadlocks and inconsistencies (this is much faster than a general purpose concurrent database). Scripts also run in this parallel system, but their access to the game state is carefully restricted as explained earlier. But in the end, scripts also need to modify data, and do so in a consistent way. Tasks solve this issue, but do so in the most pessimistic possible way, by being single threaded. Therefore script developers should use them in moderation. Consider the “random winner” semantics of control script queuing first, which are completely free performance wise, before deciding you need a task. It is often the case a concurrent problem reduces to “pick 0 or 1 winners, any winner, but never 2 or more” and the default queue semantics already provide that guarantee for attaching a specific model/private pair.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; is provided with &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt;, therefore it can queue tasks itself. But unlike controller queuing tasks, which are guaranteed to run on the same frame, tasks queued from tasks are guaranteed to ''not'' run on the same frame, on purpose. They are deliberately stored away and forced a delay of 6 sim-seconds. This is to avoid misuse of tasks, and infinite looping.&lt;br /&gt;
&lt;br /&gt;
This behavior might even be desirable in certain scripts, for example if you are developing some stateful signal system and you need some kind of “cleanup” task that makes sure some signal being owned by some train is still the focus of said train. You can deliberately queue tasks for future simulation frames with &amp;lt;code&amp;gt;queue_task_at&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;deadline&amp;lt;/code&amp;gt; is expressed as microseconds since the start of the current save world. You can obtain the current simulation frame &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; value with &amp;lt;code&amp;gt;Extrapolator::clock_us()&amp;lt;/code&amp;gt;, like in this example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;    // schedule task to run 10 sim-s from now&lt;br /&gt;
    sc.queue_task_at(task, ctx.extrapolator.clock_us() + 10000000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-controlctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ControlCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ControlCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    sim: &amp;amp;amp;Sim,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim controller scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects, and associated script stuct objects.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB): &amp;amp;amp;Script&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-eventctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type EventCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct EventCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim event handler scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    schedule_station_event: std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestationevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStationEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStationEvent {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing scheduled stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-script&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Script ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Script {&lt;br /&gt;
    id: ID&amp;amp;lt;Script&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::kind(self: &amp;amp;amp;Signal): mut SignalKind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the signal kind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStationEvent&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStationEvent&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Script&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::clock_us(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current microseconds since the creation of this saved game. This is used as the timing root of the simulation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second since 1970-01-01:00:00:00.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
Probe a track position for train reservations and occupations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Seconds since 1970-01-01:00:00:00 for Monday 00:00:00 of the current week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
Advance the iterator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function wants to change the train path, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    PassAtSpeed,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheckresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheckResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalCheckResult {&lt;br /&gt;
    speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores extra information associated with the result of the signal check. The ‘speed’ parameter is used with the SignalCheck::PassAtSpeed return, ignored otherwise.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-sim&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Sim ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Sim {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of the simulation state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Sim::view&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Sim, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A proxy mutable API to the simulation engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(self: &amp;amp;amp;mut SimController, train: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=542</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=542"/>
		<updated>2025-11-29T11:09:27Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used in game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration, integer division or arbitrary setting of pointers and references, and most data exposed to scripts is read-only, strictly enforced by the language. Any expression result which could result in an out of bounds or invalid memory access must be checked for validity, and the API design together with the type system enforces it.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
pub struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::event_event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;ProbeCheck,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalCheckResult&lt;br /&gt;
): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- VisMod? 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' NAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Script&amp;lt;/code&amp;gt; (with restrictions)&lt;br /&gt;
&lt;br /&gt;
Structs extending game types for player extensions must be declared as &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt;. When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
To read struct objects from script code they must be looked up using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API. Therefore only functions provided with &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt; object (or a context object with contains &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt;) can look up these objects. But you can pass around &amp;lt;code&amp;gt;DB&amp;amp;amp;&amp;lt;/code&amp;gt; as a parameter without any lifetime restrictions, since it’s a purely read only API. This API also works for non-pub structs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= ctx.db.view&amp;amp;lt;Example&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    log(&amp;amp;quot;v = @&amp;amp;quot;, config.v);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;pub-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== pub structs ====&lt;br /&gt;
&lt;br /&gt;
As explained earlier, &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs are the user interface of your scripts. They are exposed in the UI as input forms, and their &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;s can give some control over this rendering. Conceptually they are owned by the player of the game as part of the game object database, by attaching them to a game model object in the database, not the script. Scripts do not have any capability to create, edit or delete objects of &amp;lt;code&amp;gt;pub struct&amp;lt;/code&amp;gt;s. It is always the player who decides when to create a new object of these structs by interacting in the UI. Scripts can then read, and only read, the content of these objects, by using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API presented earlier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs have a very powerful capability: they have limited support for forward schema evolution. This means that the script developer can add to, and reorder, fields in &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, and the game runtime will be able keep the contents of the other fields intact. This is very important to respect the input data by the player. If you rename &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs or their fields, or change their types, the player input data will be lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;non-pub-or-private-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Non-pub (or private) structs ====&lt;br /&gt;
&lt;br /&gt;
Non-&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, also called private structs, are conceptually owned by the script as a part of the simulation, not the player. Their contents are assumed to be a black box by the rest of the game. Scripts are allowed to create and modify objects of these structs during their execution, which are automatically deleted at the end of the simulation frame. It is also possible to attach these structs to existing game model objects to extend their lifetime beyond the current frame. In this case their lifetime becomes the same as the game object, and they can be retrieved in later frames for reading, deleted or overwritten as desired.&lt;br /&gt;
&lt;br /&gt;
Private structs ''do not support schema evolution''. Changing field types, field names, reordering of fields, even just adding new fields at the end, will always result in losing all existing attached objects of the given struct. Some operations like resetting the simulation will also erase attached objects, because they are considered simulation state, not player created objects.&lt;br /&gt;
&lt;br /&gt;
Private structs support dynamic memory allocation. All private struct definitions automatically create a &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; method for the struct:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct PrivData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let ro &amp;amp;amp;= ctx.db.view&amp;amp;lt;PrivData&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    let rw &amp;amp;amp;mut= PrivData::clone(ro);&lt;br /&gt;
    rw.v = 100;&lt;br /&gt;
    let empty &amp;amp;amp;mut= PrivData::new();&lt;br /&gt;
    empty.v = 200;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The objects allocated by &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; are always deleted at the end of the current simulation frame. Their lifetime can be extended beyond the current frame by attaching them to a game object, like &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, so their lifetime becomes the same as the attached object. The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API has methods for attaching and erasing these object.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;host-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Host structs ====&lt;br /&gt;
&lt;br /&gt;
Many of the exposed game APIs are also based around structs. These structs do not follow any of the previous rules. Some have special capabilities, for example simple structs like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt; are ''value objects'': they can be copied and passed around like any &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; would. Some others are strictly locked down and serve as very little beyond a way to keep a pointer safe. In general, when working with game API structs, assume they are what would be called ''move only'' in C++. And NimbyScript has no move operator or semantics, so in essence assume they are immutable, immobile references, except when documented otherwise (like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As an aside, all script declared &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; or not) are also always ''move only'', and always “owned” by some external entity. This is why the APIs for their manipulation are always based on pointers and references, even for private structs. It is not possible to create plain, stack allocated values of script structs, or to use them as fields in structs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version:&lt;br /&gt;
&lt;br /&gt;
* Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
* Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums)&lt;br /&gt;
* For pub structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* For private structs: &amp;lt;code&amp;gt;ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In pub structs these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- 'let' BindBody 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- 'let' BindBody ';'&lt;br /&gt;
BindBody    &amp;amp;lt;- NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' 'let' BindBody BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- ColonNAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere, pointer types cannot be deferenced, therefore cannot be used in dot expressions. But built-in functions &amp;lt;code&amp;gt;is_null(v): bool&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;is_valid(v): bool&amp;lt;/code&amp;gt; are usable with any pointer type and value.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;extensions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Extensions =&lt;br /&gt;
&lt;br /&gt;
Extending game database struct data with &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt; can also be used to extend the game code. The mechanism to do so is to first declare a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;ing a game database object (with or without fields). Then create a specifically named and parametrized function which will be called by the game under certain situations, for certain kinds of objects.&lt;br /&gt;
&lt;br /&gt;
All extension functions take a &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter which is a reference to the struct which it is method of, called &amp;lt;code&amp;gt;Example&amp;lt;/code&amp;gt; in the following sections. Replace it with your struct name. The rest of the parameters are fixed and must be reproduced exactly as-is.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
Event functions are called as part of the core simulation engine. They are meant to be focused in features and quick to execute. These functions might be called thousands of times per simulation frame, including multiple redundant times. Their capability to change the simulation behavior is usually very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_check&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_check ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalCheckResult&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;PassAtSpeed&amp;lt;/code&amp;gt; is for all path checking and reservation purposes equivalent to &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt;, but it will create a max speed (set in &amp;lt;code&amp;gt;result.speed&amp;lt;/code&amp;gt;) restriction obstacle at the signal point when &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; is being called while the train is at braking distance from the signal, before it passes-by it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_change_path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_change_path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_change_path(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The current path check result of this signal for the passed train is passed as &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;. This already includes any results from &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_pass_by&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_pass_by ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_pass_by(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; function on the exact simulation frame a train passes by the exact point of the signal on the track.&lt;br /&gt;
&lt;br /&gt;
This function has no return result. Instead, since it has a predictably low call rate compared to the other events, it is the only event function with access to the powerful &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_marker_reserved&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_marker_reserved ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given marker signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; any time the reservation check algorithm is tracing a path which goes over the marker signal, on any direction, giving it the chance to report an arbitrary train as the reserver of that point on the track.&lt;br /&gt;
&lt;br /&gt;
This signal has a potential huge call rate, and for this reason it is given very little access to the APIs. The intention is that all the state required by this signal is calculated somewhere else and attached to the signal as a private struct object, or to some object reachable from it. Don’t worry about filtering for the “same train” cases, this is automatically done.&lt;br /&gt;
&lt;br /&gt;
If no reservation is desired, use the &amp;lt;code&amp;gt;empty&amp;lt;/code&amp;gt; global method available in all &amp;lt;code&amp;gt;ID&amp;amp;lt;Class&amp;amp;gt;&amp;lt;/code&amp;gt; types: &amp;lt;code&amp;gt;return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal {}&lt;br /&gt;
struct Owner {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; {&lt;br /&gt;
    // some other, more full featured script function has attached Owner to this signal,&lt;br /&gt;
    // or not, so we need to check first&lt;br /&gt;
    if let owner &amp;amp;amp;= db.view&amp;amp;lt;Owner&amp;amp;gt;(signal) {&lt;br /&gt;
        if is_valid(db.view(owner.train_id)) {&lt;br /&gt;
            return owner.train_id;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_texture_state&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_texture_state ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_texture_state(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): i64 { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment, when the game UI needs to query what is the current signal texture state index, it will call your &amp;lt;code&amp;gt;event_signal_texture_state&amp;lt;/code&amp;gt;, with some potential caching to keep the call rate lower. In any case the call rate of this function is potentially very large when the user zooms out the map, so make sure to keep its code as efficient as possible. For this same reason it is given very little access to the APIs.&lt;br /&gt;
&lt;br /&gt;
The return value indicates which signal texture state is to be used. If it’s -1 or lower, the default algorithm will be used to select the texture index. If it’s 0 or larger, it will select the texture in the same order as the &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; lines in the &amp;lt;code&amp;gt;SignalTextures&amp;lt;/code&amp;gt;. Larger values than the number of states will be clamped to the last state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;controllers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Controllers ==&lt;br /&gt;
&lt;br /&gt;
Controller functions are called at a low frame rate compared to the overall simulation, with an (unchangeable) rate of once in 6 sim-seconds. In exchange they can invoke powerful ''commands'' as their execution result, and do not need any specific event or trigger to run, other than their enforced timer&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-control_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train control_train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct HateDepots extend Train {}&lt;br /&gt;
pub fn HateDepots::control_train(&lt;br /&gt;
    self: &amp;amp;amp;HateDepots,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    // train is already removed from the tracks, don't interfere with potential attempts at shift assignation&lt;br /&gt;
    if is_null(motion.presence.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is running a schedule, don't interfere&lt;br /&gt;
    if is_valid(motion.schedule_dispatch.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is present, but it is not running a schedule, so despawn it&lt;br /&gt;
    sc.queue_train_intervention(train);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The train motion engine will call train controllers after the entire simulation for a given frame is done, and all threads are finished. Command execution will only happen after all train controllers for a given frame are done. In other words, train controllers are given a consistent, read-only snapshot of the train sim, and queue up work to be executed by the sim. They never directly change the sim in any way, allowing train controller execution to be fully parallel.&lt;br /&gt;
&lt;br /&gt;
After all controllers are run, and all their non-task commands are executed, tasks are executed. Read more about tasks later on. Any tasks with a deadline which expired in this frame a run at this time too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontroller-command-queue&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== SimController command queue ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; object implements an API to control the simulation, including modification of some parameters and behaviors. It is also responsible for attaching and erasing private struct data from game objects, on behalf of scripts. The execution of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; is based on a command queue. Every call queues a command and returns immediately to the script code, without making any changes to the game state. Therefore the game state never changes while the script code is running.&lt;br /&gt;
&lt;br /&gt;
For control scripts, commands are executed asynchronously, there is no guaranteed order of execution! You must prepare your code and data for this design. For tasks scripts commands are executed in order and in isolation. You can queue up tasks from control scripts when you need to guarantee data consistency beyond “pick a random winner”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_intervention&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_intervention ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks, releases its schedule shift (if any), and deletes and refunds its pax (if any). No other cost other than pax refunds is issued. This function can be used as a general “despawn the train” feature, not just for exceptional circumstances.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_warp&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_warp ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks and repositions it at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, re-pathing it to its currently scheduled destination (if any), and setting its speed to 0. This is basically a train wormhole. The train keeps its shift and pax, if any.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_drive_to&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_drive_to ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Re-paths the train path to end at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, without any changes to its shift or pax (if any). It is possible for any future &amp;lt;code&amp;gt;queue_train_drive_to&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; to reset this path at any point, losing the destination. “Queue” here is used as part of the SimController API semantics, it does not mean the train keeps a queue of positions to reach. If the path is not interrupted and the train reaches &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; it will re-path itself towards its current scheduled stop, if it has any, or brake to a stop if unassigned. If &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; was also in the stop area set for its current scheduled stop it will also brake to stop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_attach&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_attach ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the attachment of the &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) to the &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt;, which must be of one of the following types: &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attached objects can be accessed with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt; at some point in the future. If called from a controller function, the attached object will be accessible after all controller functions are done for a given frame. If called from a task, he attached object will be accessible immediately after the task returns, and before any other task is executed. In other words, tasks are transaction-like, in the sense they view an immutable snapshot of the game state, and any changes they queue are executed before any other task, and then visible from these other tasks.&lt;br /&gt;
&lt;br /&gt;
Attaching an object of a given private struct type when it already exists attached to a &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt; will overwrite it. This is how private data is updated from scripting: by using &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; to copy any existing data, modifying the copy, then calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; to replace the existing data. Therefore it is a good idea to keep your private structs small. Only one instance of a given private struct type can be attached to any particular model object, but you can attach as many different private struct types as you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_erase&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_erase ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the erasure of &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt;, which must obtained using with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt;. Trying to erase temporary objects (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) is ignored. The execution of the queued erase commands is analog to the &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; case. In particular a sequences of attach and erase queued from controllers will produce undefined results (impossible to predict which attach and/or erase wins). For example multiple attach from a controller for the same model_obj and private struct type will implicitly pick a singular “winner” attach, but the script does not have any control over which one. Sequences of attach and erase queued from tasks are strictly ordered and isolated, so they produce consistent results, in the same order they were queued in the task script, without any concurrent changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task-and-simcontrollerqueue_task_at&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task and SimController::queue_task_at ===&lt;br /&gt;
&lt;br /&gt;
These functions are documented in the next section.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
Tasks are a very special kind of command which allows scripts to dynamically queue “future work”. Scripts with access to &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; can call this function to queue up a task for future script execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; must be of a private struct type which implements &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example { ... }&lt;br /&gt;
pub fn Example::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
For example, a train controller script could decide it needs to delay some decision into a task for data consistency reasons (other controllers are running at the same time), and delegate into a task rather than directly calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ControlTrain extends Train { ... }&lt;br /&gt;
pub fn ControlTrain::control_train(&lt;br /&gt;
    self: &amp;amp;amp;ControlTrain,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    task.train_id = train.id;&lt;br /&gt;
    task.v = some_data_from_somewhere;&lt;br /&gt;
    task.prio = 42; // or something smarter, like from ControlTrain, other objects, etc.&lt;br /&gt;
    sc.queue_task(task);&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
struct Task {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
struct SomeData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
pub fn Task::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    let train &amp;amp;amp;= ctx.db.view(self.train_id) else { return; }&lt;br /&gt;
    if let existing &amp;amp;amp;= ctx.db.view&amp;amp;lt;SomeData&amp;amp;gt;(train) {&lt;br /&gt;
        if existing.prio &amp;amp;gt;= self.prio {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    let data = SomeData::new();&lt;br /&gt;
    data.v = self.v;&lt;br /&gt;
    data.prio = self.prio;&lt;br /&gt;
    sc.queue_attach(train, data);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the previous example, maybe &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; will be called multiple times because multiple &amp;lt;code&amp;gt;ControlTrain::control_train()&amp;lt;/code&amp;gt; instances queued objects of &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;, but each execution will be single threaded, and all its queued &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; commands will be executed just after the call is done and before any other &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; call (for &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; or any other struct type), therefore the algorithm to pick a winner based on an explicit priority works.&lt;br /&gt;
&lt;br /&gt;
As mentioned, task execution is single threaded. The game does not feature a real concurrent database, instead all concurrent access is bespoke and very carefully designed to avoid deadlocks and inconsistencies (this is much faster than a general purpose concurrent database). Scripts also run in this parallel system, but their access to the game state is carefully restricted as explained earlier. But in the end, scripts also need to modify data, and do so in a consistent way. Tasks solve this issue, but do so in the most pessimistic possible way, by being single threaded. Therefore script developers should use them in moderation. Consider the “random winner” semantics of control script queuing first, which are completely free performance wise, before deciding you need a task. It is often the case a concurrent problem reduces to “pick 0 or 1 winners, any winner, but never 2 or more” and the default queue semantics already provide that guarantee for attaching a specific model/private pair.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; is provided with &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt;, therefore it can queue tasks itself. But unlike controller queuing tasks, which are guaranteed to run on the same frame, tasks queued from tasks are guaranteed to ''not'' run on the same frame, on purpose. They are deliberately stored away and forced a delay of 6 sim-seconds. This is to avoid misuse of tasks, and infinite looping.&lt;br /&gt;
&lt;br /&gt;
This behavior might even be desirable in certain scripts, for example if you are developing some stateful signal system and you need some kind of “cleanup” task that makes sure some signal being owned by some train is still the focus of said train. You can deliberately queue tasks for future simulation frames with &amp;lt;code&amp;gt;queue_task_at&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;deadline&amp;lt;/code&amp;gt; is expressed as microseconds since the start of the current save world. You can obtain the current simulation frame &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; value with &amp;lt;code&amp;gt;Extrapolator::clock_us()&amp;lt;/code&amp;gt;, like in this example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;    // schedule task to run 10 sim-s from now&lt;br /&gt;
    sc.queue_task_at(task, ctx.extrapolator.clock_us() + 10000000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-controlctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ControlCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ControlCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    sim: &amp;amp;amp;Sim,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim controller scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects, and associated script stuct objects.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB): &amp;amp;amp;Script&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-eventctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type EventCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct EventCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim event handler scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    schedule_station_event: std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestationevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStationEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStationEvent {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing scheduled stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-script&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Script ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Script {&lt;br /&gt;
    id: ID&amp;amp;lt;Script&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::kind(self: &amp;amp;amp;Signal): mut SignalKind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the signal kind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStationEvent&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStationEvent&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Script&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::clock_us(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current microseconds since the creation of this saved game. This is used as the timing root of the simulation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second since 1970-01-01:00:00:00.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
Probe a track position for train reservations and occupations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Seconds since 1970-01-01:00:00:00 for Monday 00:00:00 of the current week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
Advance the iterator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function wants to change the train path, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    PassAtSpeed,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheckresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheckResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalCheckResult {&lt;br /&gt;
    speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores extra information associated with the result of the signal check. The ‘speed’ parameter is used with the SignalCheck::PassAtSpeed return, ignored otherwise.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-sim&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Sim ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Sim {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of the simulation state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Sim::view&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Sim, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A proxy mutable API to the simulation engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(self: &amp;amp;amp;mut SimController, train: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=541</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=541"/>
		<updated>2025-11-25T10:21:57Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used in game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration, integer division or arbitrary setting of pointers and references, and most data exposed to scripts is read-only, strictly enforced by the language. Any expression result which could result in an out of bounds or invalid memory access must be checked for validity, and the API design together with the type system enforces it.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
pub struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::event_event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;ProbeCheck,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalCheckResult&lt;br /&gt;
): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- VisMod? 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' NAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;Script&amp;lt;/code&amp;gt; (with restrictions)&lt;br /&gt;
&lt;br /&gt;
Structs extending game types for player extensions must be declared as &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt;. When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
To read struct objects from script code they must be looked up using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API. Therefore only functions provided with &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt; object (or a context object with contains &amp;lt;code&amp;gt;DB&amp;lt;/code&amp;gt;) can look up these objects. But you can pass around &amp;lt;code&amp;gt;DB&amp;amp;amp;&amp;lt;/code&amp;gt; as a parameter without any lifetime restrictions, since it’s a purely read only API. This API also works for non-pub structs.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= ctx.db.view&amp;amp;lt;Example&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    log(&amp;amp;quot;v = @&amp;amp;quot;, config.v);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;pub-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== pub structs ====&lt;br /&gt;
&lt;br /&gt;
As explained earlier, &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs are the user interface of your scripts. They are exposed in the UI as input forms, and their &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;s can give some control over this rendering. Conceptually they are owned by the player of the game as part of the game object database, by attaching them to a game model object in the database, not the script. Scripts do not have any capability to create, edit or delete objects of &amp;lt;code&amp;gt;pub struct&amp;lt;/code&amp;gt;s. It is always the player who decides when to create a new object of these structs by interacting in the UI. Scripts can then read, and only read, the content of these objects, by using the &amp;lt;code&amp;gt;DB::view&amp;amp;lt;ScriptStruct&amp;amp;gt;(bj: &amp;amp;amp;GameObject): *ScriptStruct&amp;lt;/code&amp;gt; API presented earlier.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs have a very powerful capability: they have limited support for forward schema evolution. This means that the script developer can add to, and reorder, fields in &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, and the game runtime will be able keep the contents of the other fields intact. This is very important to respect the input data by the player. If you rename &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs or their fields, or change their types, the player input data will be lost.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;non-pub-or-private-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Non-pub (or private) structs ====&lt;br /&gt;
&lt;br /&gt;
Non-&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; structs, also called private structs, are conceptually owned by the script as a part of the simulation, not the player. Their contents are assumed to be a black box by the rest of the game. Scripts are allowed to create and modify objects of these structs during their execution, which are automatically deleted at the end of the simulation frame. It is also possible to attach these structs to existing game model objects to extend their lifetime beyond the current frame. In this case their lifetime becomes the same as the game object, and they can be retrieved in later frames for reading, deleted or overwritten as desired.&lt;br /&gt;
&lt;br /&gt;
Private structs ''do not support schema evolution''. Changing field types, field names, reordering of fields, even just adding new fields at the end, will always result in losing all existing attached objects of the given struct. Some operations like resetting the simulation will also erase attached objects, because they are considered simulation state, not player created objects.&lt;br /&gt;
&lt;br /&gt;
Private structs support dynamic memory allocation. All private struct definitions automatically create a &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and a &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; method for the struct:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct PrivData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
fn f(ctx: &amp;amp;amp;EventCtx, signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let ro &amp;amp;amp;= ctx.db.view&amp;amp;lt;PrivData&amp;amp;gt;(signal) else { return; }&lt;br /&gt;
    let rw &amp;amp;amp;mut= PrivData::clone(ro);&lt;br /&gt;
    rw.v = 100;&lt;br /&gt;
    let empty &amp;amp;amp;mut= PrivData::new();&lt;br /&gt;
    empty.v = 200;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The objects allocated by &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; are always deleted at the end of the current simulation frame. Their lifetime can be extended beyond the current frame by attaching them to a game object, like &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, so their lifetime becomes the same as the attached object. The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API has methods for attaching and erasing these object.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;host-structs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Host structs ====&lt;br /&gt;
&lt;br /&gt;
Many of the exposed game APIs are also based around structs. These structs do not follow any of the previous rules. Some have special capabilities, for example simple structs like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt; are ''value objects'': they can be copied and passed around like any &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; would. Some others are strictly locked down and serve as very little beyond a way to keep a pointer safe. In general, when working with game API structs, assume they are what would be called ''move only'' in C++. And NimbyScript has no move operator or semantics, so in essence assume they are immutable, immobile references, except when documented otherwise (like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
As an aside, all script declared &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; or not) are also always ''move only'', and always “owned” by some external entity. This is why the APIs for their manipulation are always based on pointers and references, even for private structs. It is not possible to create plain, stack allocated values of script structs, or to use them as fields in structs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version:&lt;br /&gt;
&lt;br /&gt;
* Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
* Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;&lt;br /&gt;
* Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums)&lt;br /&gt;
* Some values of the game type &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All of these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- 'let' BindBody 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- 'let' BindBody ';'&lt;br /&gt;
BindBody    &amp;amp;lt;- NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' 'let' BindBody BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= ctx.db.view&amp;amp;lt;SpeedTrap&amp;amp;gt;(signal) {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- ColonNAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere, pointer types cannot be deferenced, therefore cannot be used in dot expressions. But built-in functions &amp;lt;code&amp;gt;is_null(v): bool&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;is_valid(v): bool&amp;lt;/code&amp;gt; are usable with any pointer type and value.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;extensions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Extensions =&lt;br /&gt;
&lt;br /&gt;
Extending game database struct data with &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt; can also be used to extend the game code. The mechanism to do so is to first declare a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;ing a game database object (with or without fields). Then create a specifically named and parametrized function which will be called by the game under certain situations, for certain kinds of objects.&lt;br /&gt;
&lt;br /&gt;
All extension functions take a &amp;lt;code&amp;gt;self&amp;lt;/code&amp;gt; parameter which is a reference to the struct which it is method of, called &amp;lt;code&amp;gt;Example&amp;lt;/code&amp;gt; in the following sections. Replace it with your struct name. The rest of the parameters are fixed and must be reproduced exactly as-is.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;events&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
Event functions are called as part of the core simulation engine. They are meant to be focused in features and quick to execute. These functions might be called thousands of times per simulation frame, including multiple redundant times. Their capability to change the simulation behavior is usually very limited.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_check&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_check ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_check(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalCheckResult&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;PassAtSpeed&amp;lt;/code&amp;gt; is for all path checking and reservation purposes equivalent to &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt;, but it will create a max speed (set in &amp;lt;code&amp;gt;result.speed&amp;lt;/code&amp;gt;) restriction obstacle at the signal point when &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt; is being called while the train is at braking distance from the signal, before it passes-by it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_change_path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_change_path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_change_path(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The current path check result of this signal for the passed train is passed as &amp;lt;code&amp;gt;check&amp;lt;/code&amp;gt;. This already includes any results from &amp;lt;code&amp;gt;event_signal_check&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_pass_by&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_pass_by ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_pass_by(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;EventCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_pass_by&amp;lt;/code&amp;gt; function on the exact simulation frame a train passes by the exact point of the signal on the track.&lt;br /&gt;
&lt;br /&gt;
This function has no return result. Instead, since it has a predictably low call rate compared to the other events, it is the only event function with access to the powerful &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; API.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal-event_signal_marker_reserved&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Signal event_signal_marker_reserved ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given marker signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;event_signal_marker_reserved&amp;lt;/code&amp;gt; any time the reservation check algorithm is tracing a path which goes over the marker signal, on any direction, giving it the chance to report an arbitrary train as the reserver of that point on the track.&lt;br /&gt;
&lt;br /&gt;
This signal has a potential huge call rate, and for this reason it is given very little access to the APIs. The intention is that all the state required by this signal is calculated somewhere else and attached to the signal as a private struct object, or to some object reachable from it. Don’t worry about filtering for the “same train” cases, this is automatically done.&lt;br /&gt;
&lt;br /&gt;
If no reservation is desired, use the &amp;lt;code&amp;gt;empty&amp;lt;/code&amp;gt; global method available in all &amp;lt;code&amp;gt;ID&amp;amp;lt;Class&amp;amp;gt;&amp;lt;/code&amp;gt; types: &amp;lt;code&amp;gt;return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct Example extends Signal {}&lt;br /&gt;
struct Owner {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
}&lt;br /&gt;
pub fn Example::event_signal_marker_reserved(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): ID&amp;amp;lt;Train&amp;amp;gt; {&lt;br /&gt;
    // some other, more full featured script function has attached Owner to this signal,&lt;br /&gt;
    // or not, so we need to check first&lt;br /&gt;
    if let owner &amp;amp;amp;= db.view&amp;amp;lt;Owner&amp;amp;gt;(signal) {&lt;br /&gt;
        if is_valid(db.view(owner.train_id)) {&lt;br /&gt;
            return owner.train_id;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return ID&amp;amp;lt;Train&amp;amp;gt;::empty();&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;controllers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Controllers ==&lt;br /&gt;
&lt;br /&gt;
Controller functions are called at a low frame rate compared to the overall simulation, with an (unchangeable) rate of once in 6 sim-seconds. In exchange they can invoke powerful ''commands'' as their execution result, and do not need any specific event or trigger to run, other than their enforced timer&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;train-control_train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Train control_train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct HateDepots extend Train {}&lt;br /&gt;
pub fn HateDepots::control_train(&lt;br /&gt;
    self: &amp;amp;amp;HateDepots,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    // train is already removed from the tracks, don't interfere with potential attempts at shift assignation&lt;br /&gt;
    if is_null(motion.presence.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is running a schedule, don't interfere&lt;br /&gt;
    if is_valid(motion.schedule_dispatch.get()) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    // train is present, but it is not running a schedule, so despawn it&lt;br /&gt;
    sc.queue_train_intervention(train);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The train motion engine will call train controllers after the entire simulation for a given frame is done, and all threads are finished. Command execution will only happen after all train controllers for a given frame are done. In other words, train controllers are given a consistent, read-only snapshot of the train sim, and queue up work to be executed by the sim. They never directly change the sim in any way, allowing train controller execution to be fully parallel.&lt;br /&gt;
&lt;br /&gt;
After all controllers are run, and all their non-task commands are executed, tasks are executed. Read more about tasks later on. Any tasks with a deadline which expired in this frame a run at this time too.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontroller-command-queue&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== SimController command queue ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; object implements an API to control the simulation, including modification of some parameters and behaviors. It is also responsible for attaching and erasing private struct data from game objects, on behalf of scripts. The execution of &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; is based on a command queue. Every call queues a command and returns immediately to the script code, without making any changes to the game state. Therefore the game state never changes while the script code is running.&lt;br /&gt;
&lt;br /&gt;
For control scripts, commands are executed asynchronously, there is no guaranteed order of execution! You must prepare your code and data for this design. For tasks scripts commands are executed in order and in isolation. You can queue up tasks from control scripts when you need to guarantee data consistency beyond “pick a random winner”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_intervention&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_intervention ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks, releases its schedule shift (if any), and deletes and refunds its pax (if any). No other cost other than pax refunds is issued. This function can be used as a general “despawn the train” feature, not just for exceptional circumstances.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_warp&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_warp ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Removes the train from the tracks and repositions it at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, re-pathing it to its currently scheduled destination (if any), and setting its speed to 0. This is basically a train wormhole. The train keeps its shift and pax, if any.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_train_drive_to&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_train_drive_to ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Re-paths the train path to end at &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt;, without any changes to its shift or pax (if any). It is possible for any future &amp;lt;code&amp;gt;queue_train_drive_to&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;event_signal_change_path&amp;lt;/code&amp;gt; to reset this path at any point, losing the destination. “Queue” here is used as part of the SimController API semantics, it does not mean the train keeps a queue of positions to reach. If the path is not interrupted and the train reaches &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; it will re-path itself towards its current scheduled stop, if it has any, or brake to a stop if unassigned. If &amp;lt;code&amp;gt;pos&amp;lt;/code&amp;gt; was also in the stop area set for its current scheduled stop it will also brake to stop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_attach&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_attach ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the attachment of the &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) to the &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt;, which must be of one of the following types: &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Schedule&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Attached objects can be accessed with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt; at some point in the future. If called from a controller function, the attached object will be accessible after all controller functions are done for a given frame. If called from a task, he attached object will be accessible immediately after the task returns, and before any other task is executed. In other words, tasks are transaction-like, in the sense they view an immutable snapshot of the game state, and any changes they queue are executed before any other task, and then visible from these other tasks.&lt;br /&gt;
&lt;br /&gt;
Attaching an object of a given private struct type when it already exists attached to a &amp;lt;code&amp;gt;model_obj&amp;lt;/code&amp;gt; will overwrite it. This is how private data is updated from scripting: by using &amp;lt;code&amp;gt;clone&amp;lt;/code&amp;gt; to copy any existing data, modifying the copy, then calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; to replace the existing data. Therefore it is a good idea to keep your private structs small. Only one instance of a given private struct type can be attached to any particular model object, but you can attach as many different private struct types as you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_erase&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_erase ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Queues the erasure of &amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt;, which must obtained using with &amp;lt;code&amp;gt;DB::view&amp;amp;lt;Example&amp;amp;gt;(model_obj)&amp;lt;/code&amp;gt;. Trying to erase temporary objects (allocated with &amp;lt;code&amp;gt;Example::new()&amp;lt;/code&amp;gt;, or copied from an existing object with &amp;lt;code&amp;gt;Example::clone(existing)&amp;lt;/code&amp;gt;) is ignored. The execution of the queued erase commands is analog to the &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; case. In particular a sequences of attach and erase queued from controllers will produce undefined results (impossible to predict which attach and/or erase wins). For example multiple attach from a controller for the same model_obj and private struct type will implicitly pick a singular “winner” attach, but the script does not have any control over which one. Sequences of attach and erase queued from tasks are strictly ordered and isolated, so they produce consistent results, in the same order they were queued in the task script, without any concurrent changes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;simcontrollerqueue_task-and-simcontrollerqueue_task_at&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== SimController::queue_task and SimController::queue_task_at ===&lt;br /&gt;
&lt;br /&gt;
These functions are documented in the next section.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;tasks&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Tasks ==&lt;br /&gt;
&lt;br /&gt;
Tasks are a very special kind of command which allows scripts to dynamically queue “future work”. Scripts with access to &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt; can call this function to queue up a task for future script execution:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct_obj&amp;lt;/code&amp;gt; must be of a private struct type which implements &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example { ... }&lt;br /&gt;
pub fn Example::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Example,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
For example, a train controller script could decide it needs to delay some decision into a task for data consistency reasons (other controllers are running at the same time), and delegate into a task rather than directly calling &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;pub struct ControlTrain extends Train { ... }&lt;br /&gt;
pub fn ControlTrain::control_train(&lt;br /&gt;
    self: &amp;amp;amp;ControlTrain,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    ...&lt;br /&gt;
    let task = Task::new();&lt;br /&gt;
    task.train_id = train.id;&lt;br /&gt;
    task.v = some_data_from_somewhere;&lt;br /&gt;
    task.prio = 42; // or something smarter, like from ControlTrain, other objects, etc.&lt;br /&gt;
    sc.queue_task(task);&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
struct Task {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
struct SomeData {&lt;br /&gt;
    v: i64,&lt;br /&gt;
    prio: i64,&lt;br /&gt;
}&lt;br /&gt;
pub fn Task::task_run(&lt;br /&gt;
    self: &amp;amp;amp;Task,&lt;br /&gt;
    ctx: &amp;amp;amp;ControlCtx,&lt;br /&gt;
    sc: &amp;amp;amp;mut SimController&lt;br /&gt;
) {&lt;br /&gt;
    let train &amp;amp;amp;= ctx.db.view(self.train_id) else { return; }&lt;br /&gt;
    if let existing &amp;amp;amp;= ctx.db.view&amp;amp;lt;SomeData&amp;amp;gt;(train) {&lt;br /&gt;
        if existing.prio &amp;amp;gt;= self.prio {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    let data = SomeData::new();&lt;br /&gt;
    data.v = self.v;&lt;br /&gt;
    data.prio = self.prio;&lt;br /&gt;
    sc.queue_attach(train, data);&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the previous example, maybe &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; will be called multiple times because multiple &amp;lt;code&amp;gt;ControlTrain::control_train()&amp;lt;/code&amp;gt; instances queued objects of &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt;, but each execution will be single threaded, and all its queued &amp;lt;code&amp;gt;queue_attach&amp;lt;/code&amp;gt; commands will be executed just after the call is done and before any other &amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; call (for &amp;lt;code&amp;gt;Task&amp;lt;/code&amp;gt; or any other struct type), therefore the algorithm to pick a winner based on an explicit priority works.&lt;br /&gt;
&lt;br /&gt;
As mentioned, task execution is single threaded. The game does not feature a real concurrent database, instead all concurrent access is bespoke and very carefully designed to avoid deadlocks and inconsistencies (this is much faster than a general purpose concurrent database). Scripts also run in this parallel system, but their access to the game state is carefully restricted as explained earlier. But in the end, scripts also need to modify data, and do so in a consistent way. Tasks solve this issue, but do so in the most pessimistic possible way, by being single threaded. Therefore script developers should use them in moderation. Consider the “random winner” semantics of control script queuing first, which are completely free performance wise, before deciding you need a task. It is often the case a concurrent problem reduces to “pick 0 or 1 winners, any winner, but never 2 or more” and the default queue semantics already provide that guarantee for attaching a specific model/private pair.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;task_run&amp;lt;/code&amp;gt; is provided with &amp;lt;code&amp;gt;SimController&amp;lt;/code&amp;gt;, therefore it can queue tasks itself. But unlike controller queuing tasks, which are guaranteed to run on the same frame, tasks queued from tasks are guaranteed to ''not'' run on the same frame, on purpose. They are deliberately stored away and forced a delay of 6 sim-seconds. This is to avoid misuse of tasks, and infinite looping.&lt;br /&gt;
&lt;br /&gt;
This behavior might even be desirable in certain scripts, for example if you are developing some stateful signal system and you need some kind of “cleanup” task that makes sure some signal being owned by some train is still the focus of said train. You can deliberately queue tasks for future simulation frames with &amp;lt;code&amp;gt;queue_task_at&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;deadline&amp;lt;/code&amp;gt; is expressed as microseconds since the start of the current save world. You can obtain the current simulation frame &amp;lt;code&amp;gt;clock_us&amp;lt;/code&amp;gt; value with &amp;lt;code&amp;gt;Extrapolator::clock_us()&amp;lt;/code&amp;gt;, like in this example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;    // schedule task to run 10 sim-s from now&lt;br /&gt;
    sc.queue_task_at(task, ctx.extrapolator.clock_us() + 10000000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-controlctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ControlCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ControlCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    sim: &amp;amp;amp;Sim,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim controller scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects, and associated script stuct objects.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB): &amp;amp;amp;Script&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-eventctx&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type EventCtx ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct EventCtx {&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Accesible game state for sim event handler scripts.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    schedule_station_event: std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestationevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStationEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStationEvent {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing scheduled stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-script&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Script ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Script {&lt;br /&gt;
    id: ID&amp;amp;lt;Script&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::kind(self: &amp;amp;amp;Signal): mut SignalKind&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the signal kind.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStationEvent&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStationEvent&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Building&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Script&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Track&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::empty(): mut ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::clock_us(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current microseconds since the creation of this saved game. This is used as the timing root of the simulation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second since 1970-01-01:00:00:00.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
Probe a track position for train reservations and occupations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Seconds since 1970-01-01:00:00:00 for Monday 00:00:00 of the current week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
Current second of the week.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
Advance the iterator.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function wants to change the train path, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    PassAtSpeed,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheckresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheckResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalCheckResult {&lt;br /&gt;
    speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Stores extra information associated with the result of the signal check. The ‘speed’ parameter is used with the SignalCheck::PassAtSpeed return, ignored otherwise.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-sim&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Sim ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Sim {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of the simulation state.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Sim::view&amp;amp;lt;Motion&amp;amp;gt;(self: &amp;amp;amp;Sim, train_id: ID&amp;amp;lt;Train&amp;amp;gt;): *Motion&amp;lt;/pre&amp;gt;&lt;br /&gt;
Return the Motion object associated to the train ID.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-simcontroller&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SimController ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SimController {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A proxy mutable API to the simulation engine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_attach(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    model_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_erase(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_task_at(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    struct_obj: &amp;amp;lt;Generic&amp;amp;gt;,&lt;br /&gt;
    deadline: i64&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_drive_to(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_intervention(self: &amp;amp;amp;mut SimController, train: &amp;amp;amp;Train): void&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn SimController::queue_train_warp(&lt;br /&gt;
    self: &amp;amp;amp;mut SimController,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
    pos: &amp;amp;amp;Pos&lt;br /&gt;
): void&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=540</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=540"/>
		<updated>2025-11-01T17:42:31Z</updated>

		<summary type="html">&lt;p&gt;Admin: Protected &amp;quot;NimbyScript&amp;quot; ([Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite))&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used im game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration or memory allocation, and most data exposed to scripts is read-only, strictly enforced by the language.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::signal_check(db: &amp;amp;amp;DB, extrapolator: &amp;amp;amp;Extrapolator, motion: &amp;amp;amp;Motion, signal: &amp;amp;amp;Signal): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= signal.view_SpeedTrap() else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' NAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types: - &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; - &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt; - &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; - &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt; - &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt; When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Scripts cannot extend game objects by themselves. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
Given a reference to a game object, it is possible to access its struct extension object with an auto generated method that looks it up, named &amp;lt;code&amp;gt;GameObject::view_ScriptStruct()&amp;lt;/code&amp;gt; returning a pointer to the object of the struct, which can then be checked for validity.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
// fn Signal::view_Example(): *Example has been automatically generated by the previous struct definition&lt;br /&gt;
fn f(signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= signal.view_Example() else { return; }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the current language version it is not possible to create new instances of structs from scratch, even for structs which do not extend any game object. This might change in future versions of the language. Some game API functions might return new instances of structs for specific APIs when it is safe to do so, like &amp;lt;code&amp;gt;Signal::forward(): Pos&amp;lt;/code&amp;gt;, since &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; does not allocate memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version: - Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt; - Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; - Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; - Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums) - Some values of the game type &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All of these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal_check-extension-method&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== signal_check extension method ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::signal_check(&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;signal_check&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal_change_path-extension-method&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== signal_change_path extension method ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::signal_change_path(&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;signal_change_path&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- BindDef 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- BindDef ';'&lt;br /&gt;
BindDef     &amp;amp;lt;- 'let' NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Signal::view_SpeedTrap() returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= signal.view_SpeedTrap() else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' BindDef BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= signal.view_SpeedTrap() {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- NAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere, pointer types cannot be deferenced, therefore cannot be used in dot expressions. But built-in functions &amp;lt;code&amp;gt;is_null(v): bool&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;is_valid(v): bool&amp;lt;/code&amp;gt; are usable with any pointer type and value.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects in the game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    schedule_station_event: std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestationevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStationEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStationEvent {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing scheduled stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    kind: SignalKind,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStationEvent&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStationEvent&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-reservationboundarybound&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ReservationBoundaryBound ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ReservationBoundaryBound {&lt;br /&gt;
    Continue,&lt;br /&gt;
    Bound,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-reservationboundarycheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ReservationBoundaryCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ReservationBoundaryCheck {&lt;br /&gt;
    Continue,&lt;br /&gt;
    Bound,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function is successful, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=539</id>
		<title>NimbyScript</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=NimbyScript&amp;diff=539"/>
		<updated>2025-11-01T17:42:16Z</updated>

		<summary type="html">&lt;p&gt;Admin: Created page with &amp;quot;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; = Purpose =  NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used im game development, bo...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;purpose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
&lt;br /&gt;
NimbyScript is an imperative, statically typed, AOT native compiled language for scripting gameplay extensions for NIMBY Rails. It compiles down to native machine code, just like C. It has zero calling and data marshalling overhead with C/C++: a NimbyScript function is a C function. NimbyScript data types are C types. This capability makes its compiled code much faster than the usual scripting languages used im game development, both interpreted or JIT compiled. NimbyScript is AOT compiled, but the compiler is bundled as part of NIMBY Rails, and scripts are automatically compiled on (re)load from their source text, making the development experience as seamless as interpreted scripts.&lt;br /&gt;
&lt;br /&gt;
NimbyScript syntax and semantics are inspired by Rust, C and C++. But NimbyScript is not designed to be a stand alone language, and as such its bare bones standard library lacks most features found in general purpose languages and runtimes, like file I/O, networking or threads. It is an explicit goal of the language and its runtime environment to crash as little as possible. Crashing and hanging should only happen due to bugs in the NimbyScript compiler, its runtime or NIMBY Rails C++ code, never due to errors in NimbyScript code. To accomplish this the language itself lacks some common features like general purpose iteration or memory allocation, and most data exposed to scripts is read-only, strictly enforced by the language.&lt;br /&gt;
&lt;br /&gt;
This documents assumes some familiarity with compiled, native code languages like C++ or Rust. Experience with other languages can also apply, since the basic building blocks like functions and structs/objects are similar to popular languages like Javascript or Python, but other concepts like references, pointers and values will be less clear. For this reason I won’t really explain what a function or a struct is, and instead I will focus on what makes NimbyScript different from C++/Rust in concepts like references.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;syntax&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Syntax =&lt;br /&gt;
&lt;br /&gt;
The description of each syntax category starts with a PEG (Parsing Expression Grammar) description, which is copy pasted directly from the source code of the NimbyScript compiler. Its syntax is recognized by the [https://github.com/yhirose/cpp-peglib cpp-peglib] library.&lt;br /&gt;
&lt;br /&gt;
Comments are introduced by &amp;lt;code&amp;gt;//&amp;lt;/code&amp;gt; and end at the end of the current line. Whitespace is not relevant (like C++ or Rust or Javascript, unlike Python).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Top level ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopLevel    &amp;amp;lt;- (TopMeta / ConstDecl / FnDecl / StructDef / EnumDef)*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level of a NimbyScript source file is composed of a sequence of [[#script-meta|script meta]], [[#const|const definitions]], [[#fn-defintion|function definitions]], [[#struct|struct definitions]] and [[#enum|enum definitions]].&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&lt;br /&gt;
struct SpeedTrap extend Signal {&lt;br /&gt;
    max_speed: f64,&lt;br /&gt;
}&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&lt;br /&gt;
pub fn SpeedTrap::signal_check(db: &amp;amp;amp;DB, extrapolator: &amp;amp;amp;Extrapolator, motion: &amp;amp;amp;Motion, signal: &amp;amp;amp;Signal): SignalCheck {&lt;br /&gt;
    let sc &amp;amp;amp;= signal.view_SpeedTrap() else { return SignalCheck::Pass; }&lt;br /&gt;
    if let presence &amp;amp;amp;= motion.presence.get() {&lt;br /&gt;
        if presence.speed * ms_to_kmh &amp;amp;gt; sc.max_speed {&lt;br /&gt;
            log(&amp;amp;quot;speedy @!&amp;amp;quot;, motion.train_id);&lt;br /&gt;
            return SignalCheck::Stop;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return SignalCheck::Pass;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;script-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== script meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TopMeta     &amp;amp;lt;- 'script' Meta&amp;lt;/pre&amp;gt;&lt;br /&gt;
The top level &amp;lt;code&amp;gt;script meta&amp;lt;/code&amp;gt; declares some [[#meta|&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;]] information for the scripting runtime about your script. In the current scripting runtime it must declare the language version as &amp;lt;code&amp;gt;lang: nimbyscript.v1,&amp;lt;/code&amp;gt;, and the API version as &amp;lt;code&amp;gt;api: nimbyrails.v1,&amp;lt;/code&amp;gt;. This meta declaration is mandatory and exactly one should be specified per source file.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;script meta {&lt;br /&gt;
    lang: nimbyscript.v1,&lt;br /&gt;
    api: nimbyrails.v1,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== const ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ConstDecl   &amp;amp;lt;- 'const' NAME ':' Type '=' Constant ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; definitions associate a name with a (typed) numeric constant. They are similar to Rust &amp;lt;code&amp;gt;const&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;constexpr&amp;lt;/code&amp;gt;, but much more limited in capabilities. They are not equivalent to C &amp;lt;code&amp;gt;#define&amp;lt;/code&amp;gt; since they are typed. Constants are not variables: they cannot be assigned to, and their address cannot be referenced. They can only be used in place of a literal numeric constant.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;const pi: f64 = 3.14159265358979323846;&lt;br /&gt;
const ms_to_kmh: f64 = 3.6;&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== struct ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;StructDef   &amp;amp;lt;- 'struct' NAME StructExtend? '{' (!'}' (StructField / (Meta ',')) )* '}'&lt;br /&gt;
StructExtend &amp;amp;lt;- 'extend' NAME&lt;br /&gt;
StructField &amp;amp;lt;- NAME ':' Type Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions introduce new data types within the script. Structs are a data type which contains a sequence of fields, each with a name and a type. When expressions access a value or reference of the type of the struct, it can access the individual fields with a &amp;lt;code&amp;gt;struct.field&amp;lt;/code&amp;gt; notation.&lt;br /&gt;
&lt;br /&gt;
Structs can extend one of the following game types: - &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt; - &amp;lt;code&amp;gt;Station&amp;lt;/code&amp;gt; - &amp;lt;code&amp;gt;Train&amp;lt;/code&amp;gt; - &amp;lt;code&amp;gt;Line&amp;lt;/code&amp;gt; - &amp;lt;code&amp;gt;Tag&amp;lt;/code&amp;gt; When a struct extends one of these types, and its script is in use in the game session, it will be offered as an extension in the game editor UI, for each corresponding editor. If the player enables the extension for a particular object of a game type, a new object of the script struct is created, and the player is then able to give values to the fields from the game UI. This is the only way to create objects of extension structs. Scripts cannot extend game objects by themselves. Only one object of a given script struct type is allowed per game object.&lt;br /&gt;
&lt;br /&gt;
Given a reference to a game object, it is possible to access its struct extension object with an auto generated method that looks it up, named &amp;lt;code&amp;gt;GameObject::view_ScriptStruct()&amp;lt;/code&amp;gt; returning a pointer to the object of the struct, which can then be checked for validity.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example extend Signal {&lt;br /&gt;
    v: i64,&lt;br /&gt;
}&lt;br /&gt;
// fn Signal::view_Example(): *Example has been automatically generated by the previous struct definition&lt;br /&gt;
fn f(signal: &amp;amp;amp;Signal) {&lt;br /&gt;
    let config &amp;amp;amp;= signal.view_Example() else { return; }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
In the current language version it is not possible to create new instances of structs from scratch, even for structs which do not extend any game object. This might change in future versions of the language. Some game API functions might return new instances of structs for specific APIs when it is safe to do so, like &amp;lt;code&amp;gt;Signal::forward(): Pos&amp;lt;/code&amp;gt;, since &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; does not allocate memory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;field-types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== Field types ====&lt;br /&gt;
&lt;br /&gt;
Only a subset of field types are accepted with proper editing experience in the current language version: - Boolean values: &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt; - Integer values: &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; - Floating point values: &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; - Enum values: any script-defined &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; (but not game defined enums) - Some values of the game type &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;ID&amp;amp;lt;Station&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Line&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Train&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Schedule&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Signal&amp;amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ID&amp;amp;lt;Tag&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All of these types display the proper UI for editing them, including the &amp;lt;code&amp;gt;ID&amp;amp;lt;Object&amp;amp;gt;&amp;lt;/code&amp;gt; types.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;struct-meta&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
==== struct meta ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; definitions can contain a struct-level &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ProbeCheck extend Signal {&lt;br /&gt;
    meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe a track position&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    // ...&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field will replace the name of the struct in UI for its content.&lt;br /&gt;
&lt;br /&gt;
It is also possible to define a &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; for each field:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ProbeCheck extend Signal {&lt;br /&gt;
    probe: ID&amp;amp;lt;Signal&amp;amp;gt; meta {&lt;br /&gt;
        label: &amp;amp;quot;Probe&amp;amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
* The &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt; meta field is accepted for all field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
* The &amp;lt;code&amp;gt;min&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;max&amp;lt;/code&amp;gt; meta field is accepted for &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt; field types.&lt;br /&gt;
&lt;br /&gt;
=== enum ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;EnumDef     &amp;amp;lt;- 'enum' NAME '{' (!'}' EnumOption)* '}'&lt;br /&gt;
EnumOption  &amp;amp;lt;- NAME Meta? ','&amp;lt;/pre&amp;gt;&lt;br /&gt;
Enums are a scoped set of names, with no semantics or values associated to them (unlike C enums). It is possible to pass and create values of enum types, and to check if these types match one of the enum options, but the values themselves have no meaning and cannot be expressed as any other type. Enums as a type can be referred by their name, and each option can be referred like &amp;lt;code&amp;gt;EnumName::OptionName&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Enums are most often used to represent abstract states or settings. It is also a good idea to use them in place of booleans, since having to write out the full name of the enum and the option makes the code self-documenting.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Color { Red, Green, Blue, }&lt;br /&gt;
fn pick_color(v: i64, c: Color): Color {&lt;br /&gt;
    if v &amp;amp;lt; 100 {&lt;br /&gt;
        return Color::Red;&lt;br /&gt;
    }&lt;br /&gt;
    if c == Color::Green {&lt;br /&gt;
        return Color::Blue;&lt;br /&gt;
    }&lt;br /&gt;
    return Color::Blue;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
When using enums in structs, they will be displayed as a drop down menu in the game UI, and you can modify the option labels with &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum Speed {&lt;br /&gt;
    Slow meta { label: &amp;amp;quot;Allow slow trains&amp;amp;quot; },&lt;br /&gt;
    Fast meta { label: &amp;amp;quot;Allow fast trains&amp;amp;quot; },&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;fn-definition&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== fn definition ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FnDecl      &amp;amp;lt;- VisMod? 'fn' ColonNAME '(' FnArgs? ')' (':' Type)? BlockStmt&lt;br /&gt;
FnArgs      &amp;amp;lt;- FnArg (',' FnArg)*&lt;br /&gt;
FnArg       &amp;amp;lt;- NAME ':' Type&lt;br /&gt;
VisMod      &amp;amp;lt;- 'pub'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Functions, introduced by &amp;lt;code&amp;gt;fn&amp;lt;/code&amp;gt;, define a series of parameters and contain a sequence of executable statements. All executable code is contained in one or more functions, there is no top level statements. Functions are always invoked from the game runtime in response to certain events, and there is no way to independently execute code by scripts. The &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; qualifier is required for functions which are meant to be called from the game runtime, and it can be omitted for functions which are only called from within the script.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn add(a: i64, b: i64): i64 {&lt;br /&gt;
    return a + b;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some functions are called “methods”, when said functions are meant to be called with a reference of a specific object type as its first parameter, or for collecting them under the namespace of a certain object. The game extension scripting interface is based on naming certain &amp;lt;code&amp;gt;pub&amp;lt;/code&amp;gt; script functions as methods of extended structs. As an analogy, if defining structs as &amp;lt;code&amp;gt;struct extend&amp;lt;/code&amp;gt; is used to extend game object data, defining functions as methods with a certain name is used to extend the game behavior (code).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal_check-extension-method&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== signal_check extension method ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::signal_check(&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal&lt;br /&gt;
): SignalCheck { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;signal_check&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;signal_check&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;signal_check&amp;lt;/code&amp;gt; function whenever said signal is checked as part of a path check, and is a path signal.&lt;br /&gt;
&lt;br /&gt;
This function can be called multiple times per frame per train, redundantly. Your code must return a &amp;lt;code&amp;gt;SignalCheck&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalCheck::Pass&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalCheck::Stop&amp;lt;/code&amp;gt;. Your code can only make the signal more restrictive, not less. In other words, your &amp;lt;code&amp;gt;Pass&amp;lt;/code&amp;gt; will be ignored if the default path check fails. But your &amp;lt;code&amp;gt;Stop&amp;lt;/code&amp;gt; won’t be ignored if the patch check was successful, and it will stop the train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;signal_change_path-extension-method&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== signal_change_path extension method ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Example extends Signal { ... }&lt;br /&gt;
pub fn Example::signal_change_path(&lt;br /&gt;
    db: &amp;amp;amp;DB,&lt;br /&gt;
    extrapolator: &amp;amp;amp;Extrapolator,&lt;br /&gt;
    motion: &amp;amp;amp;Motion,&lt;br /&gt;
    signal: &amp;amp;amp;Signal,&lt;br /&gt;
    check: SignalCheck,&lt;br /&gt;
    result: &amp;amp;amp;mut SignalChangePathResult&lt;br /&gt;
): SignalChangePath { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;signal_change_path&amp;lt;/code&amp;gt; script functions must be defined as a method of a &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; which &amp;lt;code&amp;gt;extend&amp;lt;/code&amp;gt;s the game object &amp;lt;code&amp;gt;Signal&amp;lt;/code&amp;gt;. They must have the exact same parameters and return type as in the previous example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;signal_change_path&amp;lt;/code&amp;gt; are called when the player enables their respective &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; as an extension for a given signal in the track editor. From that moment the game simulation system which advances the train motion simulation (the &amp;lt;code&amp;gt;Extrapolator&amp;lt;/code&amp;gt;) will call your &amp;lt;code&amp;gt;signal_change_path&amp;lt;/code&amp;gt; function whenever said signal is allowed to change the path of the train, and it is a path signal.&lt;br /&gt;
&lt;br /&gt;
Under some circumstances path signals are given a chance to change the train path, by allowing them to introduce an intermediate path goal that it is not the currently scheduled stop goal. An example of this mechanic is the stop selecting signal behavior. Starting in 1.18 this capability has been extended to every path signal, but it can only be triggered by scripts implementing &amp;lt;code&amp;gt;signal_change_path&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Your code must return a &amp;lt;code&amp;gt;SignalChangePath&amp;lt;/code&amp;gt; enum value of &amp;lt;code&amp;gt;SignalChangePath::Change&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;SignalChangePath::Keep&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;Keep&amp;lt;/code&amp;gt; keeps the current train path as-is. &amp;lt;code&amp;gt;Change&amp;lt;/code&amp;gt; will try to change the current train path to a new path that ends at the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; specified in &amp;lt;code&amp;gt;result.pos&amp;lt;/code&amp;gt; (check the API reference in the bottom of this document for the full definition of &amp;lt;code&amp;gt;SignalChangePathResult&amp;lt;/code&amp;gt;). After the train reaches that position it will automatically find a path to resume its trip to its currently scheduled stop. The train path can be altered an unlimited number of times before reaching its scheduled stop, including cutting short any previously issued path by a &amp;lt;code&amp;gt;signal_change_path&amp;lt;/code&amp;gt; script.&lt;br /&gt;
&lt;br /&gt;
=== meta ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Meta        &amp;amp;lt;- 'meta' MetaMap&lt;br /&gt;
MetaVal     &amp;amp;lt;- MetaMap / MetaVec / MetaStr / MetaName / NumberText&lt;br /&gt;
MetaMap     &amp;amp;lt;- '{' MetaKV? ( ',' MetaKV )* ',' '}'&lt;br /&gt;
MetaVec     &amp;amp;lt;- '[' MetaVal? ( ',' MetaVal )* ',' ']'&lt;br /&gt;
MetaKV      &amp;amp;lt;- MetaName ':' MetaVal&lt;br /&gt;
MetaStr     &amp;amp;lt;- '&amp;amp;quot;' [^&amp;amp;quot;]* '&amp;amp;quot;'&lt;br /&gt;
MetaName    &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9.]* &amp;amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is a structured comment, which can appear associated to certain syntax elements. It has no effect in the compilation or semantics of NimbyScript source code. Its purpose is to decorate some elements with extra information for the game runtime, like UI presentation hints, which have no relevance for compiled code. Metas are similar in semantics and expressiveness to JSON. Root meta information is a map of of key-value pairs. Keys are always a name complying with the identifier rules of the language. Meta values are one of maps, vectors, strings, names (which are just strings complying with identifier rules, not requiring quotes) and numbers.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;statements&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Statements ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BlockStmt   &amp;amp;lt;- '{' (!'}' Stmt)* '}'&lt;br /&gt;
Stmt        &amp;amp;lt;- IfBindStmt / IfStmt / ForStmt / BindElseStmt / BorrowStmt / BindStmt / AssignStmt / BlockStmt / RetStmt / BreakStmt / ContinueStmt / LogStmt / ExpStmt&amp;lt;/pre&amp;gt;&lt;br /&gt;
The body of a function is composed of a sequence of statements. Statements are the executable instructions of code; if types (like &amp;lt;code&amp;gt;struct&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;enum&amp;lt;/code&amp;gt;) define the “shape of data”, statements define how to process that data. Instructions are executed in order, starting from the first statement in a block of statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;variables-and-assignment&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Variables and assignment ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BindElseStmt &amp;amp;lt;- BindDef 'else' BlockStmt&lt;br /&gt;
BindStmt    &amp;amp;lt;- BindDef ';'&lt;br /&gt;
BindDef     &amp;amp;lt;- 'let' NAME BindTypeSep? TypePattern? '=' Exp&lt;br /&gt;
BindTypeSep &amp;amp;lt;- ':'&lt;br /&gt;
AssignStmt  &amp;amp;lt;- DotExp '=' Exp ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
New variables are introduced as parameters to a function, and by using the &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; syntax. Some syntax elements of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; are optional, in particular the type signature does not need to be fully specified (this is called ''type inference'' in other languages, but I do not claim have a formal, consistent type inference capability in NimbyScript). All of the following variable definitions are equivalent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn (a1: i64) {&lt;br /&gt;
    let a2 = 1;&lt;br /&gt;
    let a3: i64 = 1;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript variables cannot be reassigned in the sense they can in C or Rust. This distinction is not important for simple, value-based types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt;, but it is important for struct types and references. In particular it means a reference variable has exactly one chance to take the address of an object: at initialization. All other assignment operations on references always reassign into the original object. This is identical to C++ references, and unlike Rust borrows.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a = 1;&lt;br /&gt;
let r &amp;amp;amp;= a; // the type of r is &amp;amp;amp;mut i64 and it points to a memory address; it is an alias of a, forever&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // output is &amp;amp;quot;1&amp;amp;quot;.&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt; is a special case of &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt; which expects an expression evaluating into a pointer on the right side of the equals, but it will create a reference rather than a pointer. Its goal is to be able to transform pointers into references safely, by explicitly handling the invalid case inside the &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; block statement. The &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt; statement must always return.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// Signal::view_SpeedTrap() returns *SpeedTrap, which is a pointer&lt;br /&gt;
// pointers can be invalid, therefore to use them as references your&lt;br /&gt;
// code has to prove to the compiler it is handling the invalid case&lt;br /&gt;
// one way of doing so is using let-else as this:&lt;br /&gt;
let sc &amp;amp;amp;= signal.view_SpeedTrap() else { return SignalCheck::Pass; }&amp;lt;/pre&amp;gt;&lt;br /&gt;
Assignment of variables is possible when the type of the variable is &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt;. The left side of an assignment is just a variable name or struct field expression, and the right side is any expression which is compatible with the left side type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;let a mut= 1;&lt;br /&gt;
a = 10;&lt;br /&gt;
log(&amp;amp;quot;a: &amp;amp;quot;, a); // 10&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;flow-control&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Flow control ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IfBindStmt  &amp;amp;lt;- 'if' BindDef BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
IfStmt      &amp;amp;lt;- 'if' Exp BlockStmt ('else' (IfStmt / IfBindStmt / BlockStmt))?&lt;br /&gt;
&lt;br /&gt;
ForStmt     &amp;amp;lt;- 'for' NAME 'in' Exp BlockStmt&lt;br /&gt;
BreakStmt   &amp;amp;lt;- 'break' ';'&lt;br /&gt;
ContinueStmt &amp;amp;lt;- 'continue' ';'&lt;br /&gt;
&lt;br /&gt;
RetStmt     &amp;amp;lt;- 'return' Exp? ';'&amp;lt;/pre&amp;gt;&lt;br /&gt;
NimbyScript supports a subset of the usual control flow statements found in C++. &amp;lt;code&amp;gt;if&amp;lt;/code&amp;gt; statements are almost full featured, with a Rust-like syntax:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if condition() {&lt;br /&gt;
}&lt;br /&gt;
else if a != b {&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A special, limited case of Rust &amp;lt;code&amp;gt;if let&amp;lt;/code&amp;gt; or C++ &amp;lt;code&amp;gt;if (auto* v = ...)&amp;lt;/code&amp;gt; is also supported, only for expressions evaluating into pointers. It is similar and has the same motivation as &amp;lt;code&amp;gt;let else&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;// another way of handling pointers safely is by proving to the compiler&lt;br /&gt;
// the code using the pointer as a reference is inside an if branch&lt;br /&gt;
// which has checked it for validity:&lt;br /&gt;
if let sc &amp;amp;amp;= signal.view_SpeedTrap() {&lt;br /&gt;
    let v = sc.max_speed;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; statements are very limited in the current version of NimbyScript. This is a deliberate design choice. Currently it is only possible to iterate using iterator types defined in the game host runtime. Free loops and loops with arbitrary conditions are not possible. &amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;for hit in extrapolator.reservation_probe(pos) {&lt;br /&gt;
    if !hit.train.id.equals(motion.train_id) {&lt;br /&gt;
        return SignalCheck::Stop;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; ends the execution of the current function and returns to the caller. Its value is required when the function returns a value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Expressions ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ExpStmt     &amp;amp;lt;- Exp ';'&lt;br /&gt;
Exp         &amp;amp;lt;- EqExp (BoolOp EqExp)?&lt;br /&gt;
BoolOp      &amp;amp;lt;- '&amp;amp;amp;&amp;amp;amp;' / '||'&lt;br /&gt;
EqExp       &amp;amp;lt;- RelExp (EqOp RelExp)?&lt;br /&gt;
EqOp        &amp;amp;lt;- '==' / '!='&lt;br /&gt;
RelExp      &amp;amp;lt;- AddExp (CmpOp AddExp)?&lt;br /&gt;
CmpOp       &amp;amp;lt;- '&amp;amp;lt;' / '&amp;amp;gt;' / '&amp;amp;gt;=' / '&amp;amp;lt;='&lt;br /&gt;
AddExp      &amp;amp;lt;- MulExp (AddOp MulExp)*&lt;br /&gt;
AddOp       &amp;amp;lt;- '+' / '-'&lt;br /&gt;
MulExp      &amp;amp;lt;- DotExp (MulOp DotExp)*&lt;br /&gt;
MulOp       &amp;amp;lt;- '*' / '/' / '%'&lt;br /&gt;
DotExp      &amp;amp;lt;- AtomExp ('.' NAME)* MethodArgsExp?&lt;br /&gt;
MethodArgsExp &amp;amp;lt;- '(' CallArgs? ')' &lt;br /&gt;
CallExp     &amp;amp;lt;- NAME '(' CallArgs? ')' &lt;br /&gt;
CallArgs    &amp;amp;lt;- Exp (',' Exp)*&lt;br /&gt;
UnaryExp    &amp;amp;lt;- UnaryOp Exp&lt;br /&gt;
UnaryOp     &amp;amp;lt;- '!' / '-'&lt;br /&gt;
AtomExp     &amp;amp;lt;- AtomPar / CallExp / Constant / UnaryExp / ColonNAME&lt;br /&gt;
AtomPar     &amp;amp;lt;- '(' Exp ')'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Expression support is similar to classic C, with some quirks around operator precedence. You might need to use parentheses more often than in other languages to ensure the semantics of your expression, but in practice it does not happen often.&lt;br /&gt;
&lt;br /&gt;
“Dot expressions” to address struct fields support chaining like &amp;lt;code&amp;gt;variable.a.b.c&amp;lt;/code&amp;gt;, but method calls like &amp;lt;code&amp;gt;variable.method()&amp;lt;/code&amp;gt; only support one level of chaining. This can be worked around with parentheses like &amp;lt;code&amp;gt;(variable1.method1()).method2()&amp;lt;/code&amp;gt; but it’s usually a better idea to use some intermediate variables.&lt;br /&gt;
&lt;br /&gt;
As explained elsewhere, pointer types cannot be deferenced, therefore cannot be used in dot expressions. But built-in functions &amp;lt;code&amp;gt;is_null(v): bool&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;is_valid(v): bool&amp;lt;/code&amp;gt; are usable with any pointer type and value.&lt;br /&gt;
&lt;br /&gt;
Type matching in expressions is very strict. You cannot subtract an &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; from an &amp;lt;code&amp;gt;f64&amp;lt;/code&amp;gt;, for example, but you can compare them. To convert types into other types there’s a family of built-in functions called &amp;lt;code&amp;gt;as_xxx()&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;xxx&amp;lt;/code&amp;gt; is the desired return type. For example &amp;lt;code&amp;gt;as_i64(v: f64): i64&amp;lt;/code&amp;gt; is one of them. This is equivalent to the C++ cast of &amp;lt;code&amp;gt;int64_t(v)&amp;lt;/code&amp;gt;. The standard library also has some rounding functions for the specific case of float to integer conversion.&lt;br /&gt;
&lt;br /&gt;
Integer division and remainder operators trigger a compilation error, to avoid division by 0 errors at runtime. Use the &amp;lt;code&amp;gt;zdiv&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;zmod&amp;lt;/code&amp;gt; library functions to do integer division, which return 0 when the divisor is 0.&lt;br /&gt;
&lt;br /&gt;
Usage of variables in expressions is regulated by a set of borrow checking rules, which are a very simplified version of the Rust borrow checking rules. The design of the game APIs has been carefully done to avoid introducing difficult borrowing situations: virtually all data offered to scripts is read-only, making borrow checking trivial and unrestricted (this also enables seamless multithreading support for scripts). For more information on the borrow checker see this [https://carloscarrasco.com/nimby-rails-may-2025/ post].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;types&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Types ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Type        &amp;amp;lt;- TypeStore? TypeMut? TypeName&lt;br /&gt;
TypeName    &amp;amp;lt;- NAME ('&amp;amp;lt;' TypeTplArgs '&amp;amp;gt;')? ('::' TypeName)*&lt;br /&gt;
TypeTplArgs &amp;amp;lt;- TypeName (',' TypeName)*&lt;br /&gt;
TypePattern &amp;amp;lt;- TypeStore? TypeMut? TypeName?&lt;br /&gt;
TypeMut     &amp;amp;lt;- 'mut'&lt;br /&gt;
TypeStore   &amp;amp;lt;- '&amp;amp;amp;' / '*'&amp;lt;/pre&amp;gt;&lt;br /&gt;
A NimbyScript type, as used in parameters and variables, is composed of 3 elements: the storage type, the mutability flag and the value type.&lt;br /&gt;
&lt;br /&gt;
The storage of a variable type indicates if it’s storing the full value of a type, or its address. Address types are references &amp;lt;code&amp;gt;&amp;amp;amp;&amp;lt;/code&amp;gt; and pointers &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;. References are very much like C++ references. Pointers are like a “unusable” reference: you cannot dereference it, but if you can prove to the compiler you are checking it for validity, it will allow you to assign it as a reference.&lt;br /&gt;
&lt;br /&gt;
Value storage variables do not have any special character. You will see some types, specially types from the game host API, cannot be used as value variables, forcing you to always use pointers or references to them.&lt;br /&gt;
&lt;br /&gt;
Native NimbyScript value types are very limited: integer (&amp;lt;code&amp;gt;'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8'&amp;lt;/code&amp;gt;), floating point (&amp;lt;code&amp;gt;'f64' / 'f32'&amp;lt;/code&amp;gt;), booleans (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;), and enum values. Under restricted situations it is also possible to create variables of simple C-like types from the game host, like the &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt; type, or iterator types. Despite this simplicity the previous type definition grammar has support for the entire set of C++ type naming. This is because although NimbyScript cannot create new objects of these types, it can access them as struct references, therefore it needs to be able to fully express these type names.&lt;br /&gt;
&lt;br /&gt;
The mutability flag is specified with &amp;lt;code&amp;gt;mut&amp;lt;/code&amp;gt; and it indicates mutating operations can be invoked on the variable. For simple types like &amp;lt;code&amp;gt;i64&amp;lt;/code&amp;gt; this can mean overwriting it with any other value, like &amp;lt;code&amp;gt;v = 2;&amp;lt;/code&amp;gt;. For structs this usually means you are allowed to call functions which take a &amp;lt;code&amp;gt;&amp;amp;amp;mut&amp;lt;/code&amp;gt; to the variable, or to directly assign values to their fields like &amp;lt;code&amp;gt;v.f = 1;&amp;lt;/code&amp;gt;. Only a few simple struct types are allowed to be fully reassigned, like &amp;lt;code&amp;gt;Pos&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;constants&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Constants ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Constant    &amp;amp;lt;- Number / Time / BoolConst&lt;br /&gt;
&lt;br /&gt;
Number      &amp;amp;lt;- NumberText NumberType?&lt;br /&gt;
NumberText  &amp;amp;lt;- &amp;amp;lt; '-'? [0-9.]+ &amp;amp;gt;&lt;br /&gt;
NumberType  &amp;amp;lt;- 'i64' / 'u64' / 'i32' / 'u32' / 'i16' / 'u16' / 'i8' / 'u8' / 'f64' / 'f32'&lt;br /&gt;
&lt;br /&gt;
Time        &amp;amp;lt;- TimeNumber TimeOp (TimeNumber? TimeOp)? (TimeNumber? TimeOp)? TimeNumber?&lt;br /&gt;
TimeNumber  &amp;amp;lt;- &amp;amp;lt; [0-9]+ &amp;amp;gt;&lt;br /&gt;
TimeOp      &amp;amp;lt;- ':'&lt;br /&gt;
&lt;br /&gt;
BoolConst   &amp;amp;lt;- 'true' / 'false'&amp;lt;/pre&amp;gt;&lt;br /&gt;
Constant expressions are terminal syntax tokes which represent a typed value. For integer numbers, given the very strict type matching rules, you might need to use suffix annotations, like: &amp;lt;code&amp;gt;let v = 1i32; let w = 1i32 + v;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;identifiers&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Identifiers ===&lt;br /&gt;
&lt;br /&gt;
NAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9]* &amp;amp;gt; ColonNAME &amp;amp;lt;- &amp;amp;lt; [a-zA-Z_][a-zA-Z_0-9:]* &amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
The names you can use for your types, functions and variables are limited to the usual plain C restrictions. An exception is made for function names, since some C++ APIs expect you implement functions as a method of a struct, so the colon character is also allowed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;debug-logs&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Debug logs ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;LogStmt     &amp;amp;lt;- 'log' '(' '&amp;amp;quot;' LogStr '&amp;amp;quot;' (',' CallArgs+)? ')' ';'&lt;br /&gt;
LogStr      &amp;amp;lt;- [^&amp;amp;quot;]*&amp;lt;/pre&amp;gt;&lt;br /&gt;
The built-in &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; generic function is used for debug logging. &amp;lt;code&amp;gt;log()&amp;lt;/code&amp;gt; takes a text string (this is one and only allowed use of strings in NimbyScript), and then zero to N arguments. It will automatically serialize these arguments as text, and it has some smarts for some game objects, like automatically printing train names if the argument is a reference to a train. Logging has a large CPU impact and it is always disabled by default; explicit manual action in the game UI by the player is required to enable it on each game session.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;standard-library&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Standard library =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;top-level-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Top level ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn abs(a: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ceil(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn exp(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn floor(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f32): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn iround(a: f64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_inf(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_nan(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f32): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn is_normal(a: f64): bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn log10(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn loge(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn max(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn min(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f32, b: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn pow(a: f64, b: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn round(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f32): f32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn sqrt(a: f64): f64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zdiv(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i16, b: i16): i16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i32, b: i32): i32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i64, b: i64): i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: i8, b: i8): i8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u16, b: u16): u16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u32, b: u32): u32&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u64, b: u64): u64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn zmod(a: u8, b: u8): u8&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;database-model&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Database model =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-building&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Building ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Building {&lt;br /&gt;
    id: ID&amp;amp;lt;Building&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-db&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type DB ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct DB {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The database of all player-created objects in the game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Building&amp;amp;gt;): *Building&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Line&amp;amp;gt;): *Line&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Schedule&amp;amp;gt;): *Schedule&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Signal&amp;amp;gt;): *Signal&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Station&amp;amp;gt;): *Station&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Tag&amp;amp;gt;): *Tag&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Track&amp;amp;gt;): *Track&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn DB::view(self: &amp;amp;amp;DB, id: ID&amp;amp;lt;Train&amp;amp;gt;): *Train&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-line&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Line ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Line {&lt;br /&gt;
    id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motion&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion {&lt;br /&gt;
    train_id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    presence: std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;,&lt;br /&gt;
    drive: std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;,&lt;br /&gt;
    timed_stop: std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;,&lt;br /&gt;
    schedule_stop: std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;,&lt;br /&gt;
    schedule_station_event: std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;,&lt;br /&gt;
    schedule_dispatch: std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiondrive&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Drive ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Drive {&lt;br /&gt;
    waiting_signal_id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    waiting_signal_last_check: i64,&lt;br /&gt;
    path: Path,&lt;br /&gt;
    goal_trace: TapeTrace,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being driven along a path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionpresence&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::Presence ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::Presence {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    speed: f64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train being present at a certain position on a track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionscheduledispatch&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleDispatch ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleDispatch {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    run: Run,&lt;br /&gt;
    run_epoch_start: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train currently assigned to a schedule shift.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestationevent&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStationEvent ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStationEvent {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing scheduled stop related to pax and auxiliary station data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motionschedulestop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::ScheduleStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::ScheduleStop {&lt;br /&gt;
    sched_id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
    station_id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a stop due to its schedule.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-motiontimedstop&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Motion::TimedStop ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Motion::TimedStop {&lt;br /&gt;
    departure_epoch_s: i64,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Simulation state of a train performing a timed stop, with a departure time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-path&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Path ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Path {&lt;br /&gt;
    found: bool,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
    pose_start: Pose,&lt;br /&gt;
    pose_goal: Pose,&lt;br /&gt;
    found_start: Pos,&lt;br /&gt;
    found_goal: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A complex path over tracks, represented a sequence of track segments, subsegments, branchs, merges and reversals, from a start Pos to a goal Pos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pos&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pos ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pos {&lt;br /&gt;
    track_id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A position on a track, with a direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Pos::flip(self: &amp;amp;amp;Pos): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-pose&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Pose ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Pose {&lt;br /&gt;
    head: Pos,&lt;br /&gt;
    tail: Pos,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Two positions on a track, with opposite orientations. Usually used as part of station stop data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-run&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Run ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Run {&lt;br /&gt;
    line_id: ID&amp;amp;lt;Line&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A projection into real time of a sequence of stops belonging to a line, with possible modified timing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-schedule&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Schedule ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Schedule {&lt;br /&gt;
    id: ID&amp;amp;lt;Schedule&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Signal ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Signal {&lt;br /&gt;
    id: ID&amp;amp;lt;Signal&amp;amp;gt;,&lt;br /&gt;
    kind: SignalKind,&lt;br /&gt;
    match_block_facing: bool,&lt;br /&gt;
    check_beyond_stops: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::backward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing backwards from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Signal::forward(self: &amp;amp;amp;Signal): mut Pos&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns the position of a train facing forward from the signal.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalkind&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalKind ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalKind {&lt;br /&gt;
    Path,&lt;br /&gt;
    Balise,&lt;br /&gt;
    Marker,&lt;br /&gt;
    OneWay,&lt;br /&gt;
    NoWay,&lt;br /&gt;
    PlatformStop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-station&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Station ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Station {&lt;br /&gt;
    id: ID&amp;amp;lt;Station&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tag&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tag ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tag {&lt;br /&gt;
    id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
    parent_id: ID&amp;amp;lt;Tag&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tags&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Tags ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Tags {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A set of tags.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, id: ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag ID is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Tags::contains(self: &amp;amp;amp;Tags, tag: &amp;amp;amp;Tag): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given tag is contained in the set.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-tapetrace&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type TapeTrace ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct TapeTrace {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
A simplified path (with no branching) over tracks, which represents a footprint of track segments and subsegments.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;Pos): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given Pos is contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::contains(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace is fully contained inside this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn TapeTrace::hits(self: &amp;amp;amp;TapeTrace, other: &amp;amp;amp;TapeTrace): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
Returns true if the given TapeTrace hits this TapeTrace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-track&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Track ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Track {&lt;br /&gt;
    id: ID&amp;amp;lt;Track&amp;amp;gt;,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-train&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Train ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Train {&lt;br /&gt;
    id: ID&amp;amp;lt;Train&amp;amp;gt;,&lt;br /&gt;
    tags: Tags,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Drive&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Drive&amp;amp;gt;): *Motion::Drive&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::Presence&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::Presence&amp;amp;gt;): *Motion::Presence&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleDispatch&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleDispatch&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleDispatch&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStationEvent&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStationEvent&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStationEvent&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::ScheduleStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;::get(&lt;br /&gt;
    self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::ScheduleStop&amp;amp;gt;&lt;br /&gt;
): *Motion::ScheduleStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-stdoptional-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type std::optional&amp;lt;Motion::TimedStop&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;::get(self: &amp;amp;amp;std::optional&amp;amp;lt;Motion::TimedStop&amp;amp;gt;): *Motion::TimedStop&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Building&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Building&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Building&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Building&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Line&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Line&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Line&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Line&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Schedule&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Schedule&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Schedule&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Schedule&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
### Type ID&lt;br /&gt;
&amp;lt;Script&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Script&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Script&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Script&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Signal&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Signal&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Signal&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Signal&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Station&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Station&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Station&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Station&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Tag&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Tag&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Tag&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Tag&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Track&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Track&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Track&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Track&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-id-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ID&amp;lt;Train&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ID&amp;amp;lt;Train&amp;amp;gt; {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ID&amp;amp;lt;Train&amp;amp;gt;::equals(self: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;, other: &amp;amp;amp;ID&amp;amp;lt;Train&amp;amp;gt;): mut bool&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;simulation&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Simulation =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-extrapolator&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type Extrapolator ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct Extrapolator {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
The simulation system tasked with train motion and scheduling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::reservation_probe(self: &amp;amp;amp;Extrapolator, pos: &amp;amp;amp;Pos): mut ScResvProbeIt&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_monday0000_epoch_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;fn Extrapolator::week_s(self: &amp;amp;amp;Extrapolator): mut i64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-reservationboundarybound&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ReservationBoundaryBound ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ReservationBoundaryBound {&lt;br /&gt;
    Continue,&lt;br /&gt;
    Bound,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-reservationboundarycheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ReservationBoundaryCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum ReservationBoundaryCheck {&lt;br /&gt;
    Continue,&lt;br /&gt;
    Bound,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt {}&amp;lt;/pre&amp;gt;&lt;br /&gt;
Iterator to query the reservations at a certain track position.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;fn ScResvProbeIt::next(self: &amp;amp;amp;mut ScResvProbeIt): *ScResvProbeIt::Result&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-scresvprobeitresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type ScResvProbeIt::Result ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct ScResvProbeIt::Result {&lt;br /&gt;
    is_occ: bool,&lt;br /&gt;
    train: &amp;amp;amp;Train,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepath&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePath ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalChangePath {&lt;br /&gt;
    Keep,&lt;br /&gt;
    Change,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalchangepathresult&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalChangePathResult ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;struct SignalChangePathResult {&lt;br /&gt;
    pos: Pos,&lt;br /&gt;
    goal_has_stop_time: bool,&lt;br /&gt;
    force_goal_reservation: bool,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
If a signal_change_path function is successful, it must set the pos field of this struct with the goal position of the new train path.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;type-signalcheck&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Type SignalCheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;enum SignalCheck {&lt;br /&gt;
    Pass,&lt;br /&gt;
    Stop,&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=Main_Page&amp;diff=373</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=Main_Page&amp;diff=373"/>
		<updated>2023-07-17T16:10:03Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
&amp;lt;div class=&amp;quot;main-wrapper&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Welcome to the NIMBY Rails wiki!&amp;lt;/strong&amp;gt;&lt;br /&gt;
This wiki is a &amp;lt;strong&amp;gt;work in progress&amp;lt;/strong&amp;gt;. You can help it grow by creating an account and contributing guides, tips or extending the existing bare bones concept pages.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;main-row&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;main-column&amp;quot; style=&amp;quot;padding-right: 30px&amp;quot;&amp;gt;&lt;br /&gt;
= Concepts =&lt;br /&gt;
&lt;br /&gt;
== [[Geographical layer]]s ==&lt;br /&gt;
''Geographical background objects provided by the game data which cannot be modified by the player''&lt;br /&gt;
*[[Population layer]]&lt;br /&gt;
*[[Admin layer]]&lt;br /&gt;
&lt;br /&gt;
== Map concepts ==&lt;br /&gt;
''Objects created by the player on top of the geographical data''&lt;br /&gt;
*[[Blueprint]]&lt;br /&gt;
*[[Track]]&lt;br /&gt;
*[[Station]]&lt;br /&gt;
*[[Signal]]&lt;br /&gt;
*[[Layer]]s&lt;br /&gt;
*[[Building]]&lt;br /&gt;
&lt;br /&gt;
== Simulation concepts ==&lt;br /&gt;
''Things that the game generates as it runs the simulation''&lt;br /&gt;
*[[Pax]]&lt;br /&gt;
*[[Dominating trip]]&lt;br /&gt;
*[[Path]]&lt;br /&gt;
*[[Accounting]]&lt;br /&gt;
*[[Satisfaction]]&lt;br /&gt;
&lt;br /&gt;
== Line concepts ==&lt;br /&gt;
*[[Line]]&lt;br /&gt;
*[[Stop]]&lt;br /&gt;
*[[Timetable]]&lt;br /&gt;
*[[Duration]]&lt;br /&gt;
*[[Custom Duration]]&lt;br /&gt;
&lt;br /&gt;
== Train concepts ==&lt;br /&gt;
*[[Train]]&lt;br /&gt;
*[[Run]]&lt;br /&gt;
*[[Order]]&lt;br /&gt;
*[[Timetable]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;main-column&amp;quot;&amp;gt;&lt;br /&gt;
= Guides =&lt;br /&gt;
== Tutorials ==&lt;br /&gt;
All tutorial pages start with &amp;quot;How to&amp;quot; and contain a step by step guide to a simple game concept.&lt;br /&gt;
Following the tutorial pages should enable you to build and run a simple network.&lt;br /&gt;
&lt;br /&gt;
*[[Quickstart guide]]&lt;br /&gt;
*[[How to build track]]&lt;br /&gt;
*[[How to build stations]]&lt;br /&gt;
*[[How to create a line]]&lt;br /&gt;
*[[How to schedule a train]]&lt;br /&gt;
&lt;br /&gt;
== Advanced ==&lt;br /&gt;
Advanced guides enable players to use optional functionality such as signals and depots which can be ignored and replaced with defaults if needed.&lt;br /&gt;
*[[How to signal a junction]]&lt;br /&gt;
*[[How to use depots]]&lt;br /&gt;
*[[How to manual timetable]]&lt;br /&gt;
*[[How to use the in-game routeplanner]]&lt;br /&gt;
*[[How to have multiple trains share a platform]]&lt;br /&gt;
&lt;br /&gt;
== Strategy ==&lt;br /&gt;
Strategy pages assume you know ''how'' something is done and consider ''why'' you might want to do it.&lt;br /&gt;
*[[Depot strategies]]&lt;br /&gt;
*[[Mapping resources]]&lt;br /&gt;
*[[Transfer hub strategy]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check out the [[NIMBY:Contents|Contents]] master page for a work in progress overview of the current content of the wiki.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:NIMBY Rails Wiki]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=Main_Page&amp;diff=372</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=Main_Page&amp;diff=372"/>
		<updated>2023-07-17T16:08:33Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
&amp;lt;div class=&amp;quot;main-wrapper&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Welcome to the NIMBY Rails wiki!&amp;lt;/strong&amp;gt;&lt;br /&gt;
This wiki is a &amp;lt;strong&amp;gt;work in progress&amp;lt;/strong&amp;gt;. You can help it grow by creating an account and contributing guides, tips or extending the existing bare bones concept pages.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;main-row&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;main-column&amp;quot;&amp;gt;&lt;br /&gt;
= Concepts =&lt;br /&gt;
&lt;br /&gt;
== [[Geographical layer]]s ==&lt;br /&gt;
''Geographical background objects provided by the game data which cannot be modified by the player''&lt;br /&gt;
*[[Population layer]]&lt;br /&gt;
*[[Admin layer]]&lt;br /&gt;
&lt;br /&gt;
== Map concepts ==&lt;br /&gt;
''Objects created by the player on top of the geographical data''&lt;br /&gt;
*[[Blueprint]]&lt;br /&gt;
*[[Track]]&lt;br /&gt;
*[[Station]]&lt;br /&gt;
*[[Signal]]&lt;br /&gt;
*[[Layer]]s&lt;br /&gt;
*[[Building]]&lt;br /&gt;
&lt;br /&gt;
== Simulation concepts ==&lt;br /&gt;
''Things that the game generates as it runs the simulation''&lt;br /&gt;
*[[Pax]]&lt;br /&gt;
*[[Dominating trip]]&lt;br /&gt;
*[[Path]]&lt;br /&gt;
*[[Accounting]]&lt;br /&gt;
*[[Satisfaction]]&lt;br /&gt;
&lt;br /&gt;
== Line concepts ==&lt;br /&gt;
*[[Line]]&lt;br /&gt;
*[[Stop]]&lt;br /&gt;
*[[Timetable]]&lt;br /&gt;
*[[Duration]]&lt;br /&gt;
*[[Custom Duration]]&lt;br /&gt;
&lt;br /&gt;
== Train concepts ==&lt;br /&gt;
*[[Train]]&lt;br /&gt;
*[[Run]]&lt;br /&gt;
*[[Order]]&lt;br /&gt;
*[[Timetable]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;main-column&amp;quot;&amp;gt;&lt;br /&gt;
= Guides =&lt;br /&gt;
== Tutorials ==&lt;br /&gt;
All tutorial pages start with &amp;quot;How to&amp;quot; and contain a step by step guide to a simple game concept.&lt;br /&gt;
Following the tutorial pages should enable you to build and run a simple network.&lt;br /&gt;
&lt;br /&gt;
*[[Quickstart guide]]&lt;br /&gt;
*[[How to build track]]&lt;br /&gt;
*[[How to build stations]]&lt;br /&gt;
*[[How to create a line]]&lt;br /&gt;
*[[How to schedule a train]]&lt;br /&gt;
&lt;br /&gt;
== Advanced ==&lt;br /&gt;
Advanced guides enable players to use optional functionality such as signals and depots which can be ignored and replaced with defaults if needed.&lt;br /&gt;
*[[How to signal a junction]]&lt;br /&gt;
*[[How to use depots]]&lt;br /&gt;
*[[How to manual timetable]]&lt;br /&gt;
*[[How to use the in-game routeplanner]]&lt;br /&gt;
*[[How to have multiple trains share a platform]]&lt;br /&gt;
&lt;br /&gt;
== Strategy ==&lt;br /&gt;
Strategy pages assume you know ''how'' something is done and consider ''why'' you might want to do it.&lt;br /&gt;
*[[Depot strategies]]&lt;br /&gt;
*[[Mapping resources]]&lt;br /&gt;
*[[Transfer hub strategy]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check out the [[NIMBY:Contents|Contents]] master page for a work in progress overview of the current content of the wiki.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:NIMBY Rails Wiki]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=Main_Page&amp;diff=309</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=Main_Page&amp;diff=309"/>
		<updated>2023-01-24T17:32:21Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;main-wrapper&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Welcome to the NIMBY Rails wiki!&amp;lt;/strong&amp;gt;&lt;br /&gt;
This wiki is a &amp;lt;strong&amp;gt;work in progress&amp;lt;/strong&amp;gt;. You can help it grow by creating an account and contributing guides, tips or extending the existing bare bones concept pages.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;main-row&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;main-column&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;strong&amp;gt;Basic concepts&amp;lt;/strong&amp;gt;&lt;br /&gt;
*[[Blueprint]]&lt;br /&gt;
*[[Track]]&lt;br /&gt;
*[[Station]]&lt;br /&gt;
*[[Signal]]&lt;br /&gt;
*[[Layer]]s&lt;br /&gt;
*[[Building]]&lt;br /&gt;
*[[Line]]&lt;br /&gt;
*[[Stop]]&lt;br /&gt;
*[[Pax]]&lt;br /&gt;
*[[Train]]&lt;br /&gt;
*[[Run]]&lt;br /&gt;
*[[Order]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;main-column&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;strong&amp;gt;Guides&amp;lt;/strong&amp;gt;&lt;br /&gt;
*[[How to build track]]&lt;br /&gt;
*[[Quickstart guide]]&lt;br /&gt;
*[[How to use depots]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check out the [[NIMBY:Contents|Contents]] master page for a work in progress overview of the current content of the wiki.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:NIMBY Rails Wiki]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=Run&amp;diff=281</id>
		<title>Run</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=Run&amp;diff=281"/>
		<updated>2023-01-06T11:27:50Z</updated>

		<summary type="html">&lt;p&gt;Admin: &amp;quot;loop&amp;quot; was misleading&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Concepts sidebar}}&lt;br /&gt;
Runs represent the act of a train stopping at all the stops of a line (or part of a line) starting at a certain time and day of the week. Runs can never be edited by the player; they are automatically generated from [[order]]s.&lt;br /&gt;
&lt;br /&gt;
[[Category:Timetable]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=Template:Concepts_sidebar&amp;diff=256</id>
		<title>Template:Concepts sidebar</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=Template:Concepts_sidebar&amp;diff=256"/>
		<updated>2022-12-27T12:33:52Z</updated>

		<summary type="html">&lt;p&gt;Admin: add some margin&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;font-size:12px; float:right;margin-left:20px&amp;quot;&lt;br /&gt;
|- style=&amp;quot;text-align:center&amp;quot;&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; style=&amp;quot;background-color:#fcff2f;&amp;quot; | NIMBY rails game concepts&amp;lt;br /&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;background-color:#ffffc7;&amp;quot; | '''[[Geographical layer|Geography]]'''&lt;br /&gt;
| &lt;br /&gt;
*[[World map]]&lt;br /&gt;
*[[Population layer]]&lt;br /&gt;
*[[Admin layer]]&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;background-color:#ffffc7;&amp;quot; | '''Map objects'''&lt;br /&gt;
|&lt;br /&gt;
*[[Blueprint]]&lt;br /&gt;
*[[Track]]&lt;br /&gt;
*[[Station]]&lt;br /&gt;
*[[Signal]]&lt;br /&gt;
*[[Layer]]s&lt;br /&gt;
*[[Building]]&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;background-color:#ffffc7;&amp;quot; | '''[[Line]] concepts'''&lt;br /&gt;
| &lt;br /&gt;
*[[Stop]]&lt;br /&gt;
*[[Timetable]]&lt;br /&gt;
*[[Duration]]&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;background-color:#ffffc7;&amp;quot; | '''[[Train]] concepts'''&amp;lt;br /&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
*[[Run]]&lt;br /&gt;
*[[Order]]&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;background-color:#ffffc7;&amp;quot; | '''[[Simulation]]'''&lt;br /&gt;
|&lt;br /&gt;
*[[Pax]]&lt;br /&gt;
**[[Origin]]&lt;br /&gt;
**[[Destination]]&lt;br /&gt;
**[[Dominating trip]]&lt;br /&gt;
*[[Path]]&lt;br /&gt;
*[[Accounting]]&lt;br /&gt;
*[[Satisfaction]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;includeonly&amp;gt;[[Category:Concepts]]&amp;lt;/includeonly&amp;gt;&lt;br /&gt;
&amp;lt;noinclude&amp;gt;[[Category:Templates]]&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=Template:Concepts_sidebar&amp;diff=255</id>
		<title>Template:Concepts sidebar</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=Template:Concepts_sidebar&amp;diff=255"/>
		<updated>2022-12-27T12:32:48Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;font-size:12px; float:right;&amp;quot;&lt;br /&gt;
|- style=&amp;quot;text-align:center; padding-left:20px&amp;quot;&lt;br /&gt;
! colspan=&amp;quot;2&amp;quot; style=&amp;quot;background-color:#fcff2f;&amp;quot; | NIMBY rails game concepts&amp;lt;br /&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;background-color:#ffffc7;&amp;quot; | '''[[Geographical layer|Geography]]'''&lt;br /&gt;
| &lt;br /&gt;
*[[World map]]&lt;br /&gt;
*[[Population layer]]&lt;br /&gt;
*[[Admin layer]]&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;background-color:#ffffc7;&amp;quot; | '''Map objects'''&lt;br /&gt;
|&lt;br /&gt;
*[[Blueprint]]&lt;br /&gt;
*[[Track]]&lt;br /&gt;
*[[Station]]&lt;br /&gt;
*[[Signal]]&lt;br /&gt;
*[[Layer]]s&lt;br /&gt;
*[[Building]]&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;background-color:#ffffc7;&amp;quot; | '''[[Line]] concepts'''&lt;br /&gt;
| &lt;br /&gt;
*[[Stop]]&lt;br /&gt;
*[[Timetable]]&lt;br /&gt;
*[[Duration]]&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;background-color:#ffffc7;&amp;quot; | '''[[Train]] concepts'''&amp;lt;br /&amp;gt;&lt;br /&gt;
|&lt;br /&gt;
*[[Run]]&lt;br /&gt;
*[[Order]]&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;background-color:#ffffc7;&amp;quot; | '''[[Simulation]]'''&lt;br /&gt;
|&lt;br /&gt;
*[[Pax]]&lt;br /&gt;
**[[Origin]]&lt;br /&gt;
**[[Destination]]&lt;br /&gt;
**[[Dominating trip]]&lt;br /&gt;
*[[Path]]&lt;br /&gt;
*[[Accounting]]&lt;br /&gt;
*[[Satisfaction]]&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;includeonly&amp;gt;[[Category:Concepts]]&amp;lt;/includeonly&amp;gt;&lt;br /&gt;
&amp;lt;noinclude&amp;gt;[[Category:Templates]]&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=Train&amp;diff=204</id>
		<title>Train</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=Train&amp;diff=204"/>
		<updated>2022-12-22T10:27:58Z</updated>

		<summary type="html">&lt;p&gt;Admin: better explanation of a train unit&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Trains carry [[pax]] from their origin [[station]] to their [[destination]] or intermediate transfer stops. Trains are composed of one or more train units in sequence. Train units are the indivisible parts of a train, like a locomotive, a passenger car, or some technical car. The game bundles [[List_of_trains|20 default trains]] and more can be added by subscribing to [[Modding|mods]]. &lt;br /&gt;
[[Category:Concepts]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=Train&amp;diff=202</id>
		<title>Train</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=Train&amp;diff=202"/>
		<updated>2022-12-21T21:04:52Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Trains carry [[pax]] from their origin [[station]] to their [[destination]] or intermediate transfer stops. Trains are composed of one or more train units in sequence, which is a category which unifies any independent carriage in a train, be it a locomotive, a passenger car, or some technical car. The game bundles [[List_of_trains|20 default trains]] and more can be added by subscribing to [[Modding|mods]]. &lt;br /&gt;
[[Category:Concepts]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=Main_Page&amp;diff=178</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=Main_Page&amp;diff=178"/>
		<updated>2022-12-13T22:59:37Z</updated>

		<summary type="html">&lt;p&gt;Admin: grammar&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;main-wrapper&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Welcome to the NIMBY Rails wiki!&amp;lt;/strong&amp;gt;&lt;br /&gt;
This wiki is a &amp;lt;strong&amp;gt;work in progress&amp;lt;/strong&amp;gt;. You can help it grow by creating an account and contributing guides, tips or extending the existing bare bones concept pages.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;main-row&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;main-column&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;strong&amp;gt;Basic concepts&amp;lt;/strong&amp;gt;&lt;br /&gt;
*[[Blueprint]]&lt;br /&gt;
*[[Track]]&lt;br /&gt;
*[[Station]]&lt;br /&gt;
*[[Signal]]&lt;br /&gt;
*[[Layer]]s&lt;br /&gt;
*[[Building]]&lt;br /&gt;
*[[Line]]&lt;br /&gt;
*[[Stop]]&lt;br /&gt;
*[[Pax]]&lt;br /&gt;
*[[Train]]&lt;br /&gt;
*[[Run]]&lt;br /&gt;
*[[Order]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;main-column&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;strong&amp;gt;Guides&amp;lt;/strong&amp;gt;&lt;br /&gt;
*[[Quickstart guide]]&lt;br /&gt;
*[[How to use depots]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check out the [[NIMBY:Contents|Contents]] master page for a work in progress overview of the current content of the wiki.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:NIMBY Rails Wiki]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=MediaWiki:Sidebar&amp;diff=176</id>
		<title>MediaWiki:Sidebar</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=MediaWiki:Sidebar&amp;diff=176"/>
		<updated>2022-12-12T11:26:27Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
* navigation&lt;br /&gt;
** mainpage|mainpage-description&lt;br /&gt;
** Category:Concepts|Concepts&lt;br /&gt;
** Category:Guide|Guides&lt;br /&gt;
** recentchanges-url|recentchanges&lt;br /&gt;
** randompage-url|randompage&lt;br /&gt;
** helppage|help-mediawiki&lt;br /&gt;
** NIMBY:Contents|Contents&lt;br /&gt;
&lt;br /&gt;
* SEARCH&lt;br /&gt;
* TOOLBOX&lt;br /&gt;
* LANGUAGES&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=MediaWiki:Sidebar&amp;diff=175</id>
		<title>MediaWiki:Sidebar</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=MediaWiki:Sidebar&amp;diff=175"/>
		<updated>2022-12-12T11:25:10Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
* navigation&lt;br /&gt;
** mainpage|mainpage-description&lt;br /&gt;
** recentchanges-url|recentchanges&lt;br /&gt;
** randompage-url|randompage&lt;br /&gt;
** helppage|help-mediawiki&lt;br /&gt;
** NIMBY:Contents|Contents&lt;br /&gt;
&lt;br /&gt;
* SEARCH&lt;br /&gt;
* TOOLBOX&lt;br /&gt;
* LANGUAGES&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=MediaWiki:Sidebar&amp;diff=174</id>
		<title>MediaWiki:Sidebar</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=MediaWiki:Sidebar&amp;diff=174"/>
		<updated>2022-12-12T11:24:45Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
* navigation&lt;br /&gt;
** mainpage|mainpage-description&lt;br /&gt;
** [[:Category:Concepts]]&lt;br /&gt;
** [[:Category:Guide]]&lt;br /&gt;
** recentchanges-url|recentchanges&lt;br /&gt;
** randompage-url|randompage&lt;br /&gt;
** helppage|help-mediawiki&lt;br /&gt;
** NIMBY:Contents|Contents&lt;br /&gt;
&lt;br /&gt;
* SEARCH&lt;br /&gt;
* TOOLBOX&lt;br /&gt;
* LANGUAGES&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=MediaWiki:Sidebar&amp;diff=173</id>
		<title>MediaWiki:Sidebar</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=MediaWiki:Sidebar&amp;diff=173"/>
		<updated>2022-12-12T11:23:02Z</updated>

		<summary type="html">&lt;p&gt;Admin: Reverted edits by Admin (talk) to last revision by Hannibal&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
* navigation&lt;br /&gt;
** mainpage|mainpage-description&lt;br /&gt;
** recentchanges-url|recentchanges&lt;br /&gt;
** randompage-url|randompage&lt;br /&gt;
** helppage|help-mediawiki&lt;br /&gt;
** NIMBY:Contents|Contents&lt;br /&gt;
&lt;br /&gt;
* SEARCH&lt;br /&gt;
* TOOLBOX&lt;br /&gt;
* LANGUAGES&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=MediaWiki:Sidebar&amp;diff=172</id>
		<title>MediaWiki:Sidebar</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=MediaWiki:Sidebar&amp;diff=172"/>
		<updated>2022-12-12T11:22:26Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
* navigation&lt;br /&gt;
** mainpage|mainpage-description&lt;br /&gt;
** recentchanges-url|recentchanges&lt;br /&gt;
** randompage-url|randompage&lt;br /&gt;
** helppage|help-mediawiki&lt;br /&gt;
** NIMBY:Contents|Contents&lt;br /&gt;
&lt;br /&gt;
* TOOLBOX&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=Main_Page&amp;diff=163</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=Main_Page&amp;diff=163"/>
		<updated>2022-12-09T16:33:23Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;main-wrapper&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Welcome to the NIMBY Rails wiki!&amp;lt;/strong&amp;gt;&lt;br /&gt;
This wiki is a &amp;lt;strong&amp;gt;work in progress&amp;lt;/strong&amp;gt;. You can help it to grow by creating an account and contributing guides, tips or extending the existing bare bones concept pages.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;main-row&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;main-column&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;strong&amp;gt;Basic concepts&amp;lt;/strong&amp;gt;&lt;br /&gt;
*[[Blueprint]]&lt;br /&gt;
*[[Track]]&lt;br /&gt;
*[[Station]]&lt;br /&gt;
*[[Signal]]&lt;br /&gt;
*[[Layer]]s&lt;br /&gt;
*[[Building]]&lt;br /&gt;
*[[Line]]&lt;br /&gt;
*[[Stop]]&lt;br /&gt;
*[[Pax]]&lt;br /&gt;
*[[Train]]&lt;br /&gt;
*[[Run]]&lt;br /&gt;
*[[Order]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;main-column&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;strong&amp;gt;Guides&amp;lt;/strong&amp;gt;&lt;br /&gt;
*[[Quickstart guide]]&lt;br /&gt;
*[[How to use depots]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check out the [[NIMBY:Contents|Contents]] master page for a work in progress overview of the current content of the wiki.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:NIMBY Rails Wiki]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=Main_Page&amp;diff=162</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=Main_Page&amp;diff=162"/>
		<updated>2022-12-09T16:33:06Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;main-wrapper&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Welcome to the NIMBY Rails wiki!&amp;lt;/strong&amp;gt;&lt;br /&gt;
This wiki is a &amp;lt;strong&amp;gt;work in progress&amp;lt;/strong&amp;gt;. You can help it to grow by creating an account and contributing guides, tips or extending the existing bare bones concept pages.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;main-row&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;main-column&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;strong&amp;gt;Basic concepts&amp;lt;/strong&amp;gt;&lt;br /&gt;
*[[Blueprint]]&lt;br /&gt;
*[[Track]]&lt;br /&gt;
*[[Station]]&lt;br /&gt;
*[[Signal]]&lt;br /&gt;
*[[Layer]]s&lt;br /&gt;
*[[Building]]&lt;br /&gt;
*[[Line]]&lt;br /&gt;
*[[Stop]]&lt;br /&gt;
*[[Pax]]&lt;br /&gt;
*[[Train]]&lt;br /&gt;
*[[Run]]&lt;br /&gt;
*[[Order]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;main-column&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;strong&amp;gt;Guides&amp;lt;/strong&amp;gt;&lt;br /&gt;
*[[Quickstart guide]]&lt;br /&gt;
*[[How to use depots]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check out the [[NIMBY:Contents|Contents]] master page for work in progress overview of the current content of the wiki.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:NIMBY Rails Wiki]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=Main_Page&amp;diff=161</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=Main_Page&amp;diff=161"/>
		<updated>2022-12-09T16:32:29Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;main-wrapper&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Welcome to the NIMBY Rails wiki!&amp;lt;/strong&amp;gt;&lt;br /&gt;
This wiki is a &amp;lt;strong&amp;gt;work in progress&amp;lt;/strong&amp;gt;. You can help it to grow by creating an account and contributing guides, tips or extending the existing bare bones concept pages.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;main-row&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;main-column&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;strong&amp;gt;Basic concepts&amp;lt;/strong&amp;gt;&lt;br /&gt;
*[[Blueprint]]&lt;br /&gt;
*[[Track]]&lt;br /&gt;
*[[Station]]&lt;br /&gt;
*[[Signal]]&lt;br /&gt;
*[[Layer]]s&lt;br /&gt;
*[[Building]]&lt;br /&gt;
*[[Line]]&lt;br /&gt;
*[[Stop]]&lt;br /&gt;
*[[Pax]]&lt;br /&gt;
*[[Train]]&lt;br /&gt;
*[[Run]]&lt;br /&gt;
*[[Order]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;main-column&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;strong&amp;gt;Guides&amp;lt;/strong&amp;gt;&lt;br /&gt;
*[[Quickstart guide]]&lt;br /&gt;
*[[How to use depots]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check out the [[Contents]] master page for work in progress overview of the current content of the wiki.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:NIMBY Rails Wiki]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=MediaWiki:Common.css&amp;diff=160</id>
		<title>MediaWiki:Common.css</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=MediaWiki:Common.css&amp;diff=160"/>
		<updated>2022-12-09T16:31:55Z</updated>

		<summary type="html">&lt;p&gt;Admin: Created page with &amp;quot;/* CSS placed here will be applied to all skins */ .main-row {   display: flex;   flex-direction: row;   flex-wrap: wrap;   width: 100%; } .main-column {   display: flex;   flex-direction: column;   flex-basis: 100%;   flex: 1; }&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* CSS placed here will be applied to all skins */&lt;br /&gt;
.main-row {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: row;&lt;br /&gt;
  flex-wrap: wrap;&lt;br /&gt;
  width: 100%;&lt;br /&gt;
}&lt;br /&gt;
.main-column {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: column;&lt;br /&gt;
  flex-basis: 100%;&lt;br /&gt;
  flex: 1;&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=Main_Page&amp;diff=159</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=Main_Page&amp;diff=159"/>
		<updated>2022-12-09T16:31:02Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;main-wrapper&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Welcome to the NIMBY Rails wiki!&amp;lt;/strong&amp;gt;&lt;br /&gt;
This wiki is a &amp;lt;strong&amp;gt;work in progress&amp;lt;/strong&amp;gt;. You can help it to grow by creating an account and contributing guides, tips or extending the existing bare bones concept pages.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;column&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;strong&amp;gt;Basic concepts&amp;lt;/strong&amp;gt;&lt;br /&gt;
*[[Blueprint]]&lt;br /&gt;
*[[Track]]&lt;br /&gt;
*[[Station]]&lt;br /&gt;
*[[Signal]]&lt;br /&gt;
*[[Layer]]s&lt;br /&gt;
*[[Building]]&lt;br /&gt;
*[[Line]]&lt;br /&gt;
*[[Stop]]&lt;br /&gt;
*[[Pax]]&lt;br /&gt;
*[[Train]]&lt;br /&gt;
*[[Run]]&lt;br /&gt;
*[[Order]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;column&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;strong&amp;gt;Guides&amp;lt;/strong&amp;gt;&lt;br /&gt;
*[[Quickstart guide]]&lt;br /&gt;
*[[How to use depots]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check out the [[Contents]] master page for work in progress overview of the current content of the wiki.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:NIMBY Rails Wiki]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=Main_Page&amp;diff=158</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=Main_Page&amp;diff=158"/>
		<updated>2022-12-09T16:29:59Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;style&amp;gt;&lt;br /&gt;
.row {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: row;&lt;br /&gt;
  flex-wrap: wrap;&lt;br /&gt;
  width: 100%;&lt;br /&gt;
}&lt;br /&gt;
.column {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: column;&lt;br /&gt;
  flex-basis: 100%;&lt;br /&gt;
  flex: 1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/style&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;wrapper&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Welcome to the NIMBY Rails wiki!&amp;lt;/strong&amp;gt;&lt;br /&gt;
This wiki is a &amp;lt;strong&amp;gt;work in progress&amp;lt;/strong&amp;gt;. You can help it to grow by creating an account and contributing guides, tips or extending the existing bare bones concept pages.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;column&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;strong&amp;gt;Basic concepts&amp;lt;/strong&amp;gt;&lt;br /&gt;
*[[Blueprint]]&lt;br /&gt;
*[[Track]]&lt;br /&gt;
*[[Station]]&lt;br /&gt;
*[[Signal]]&lt;br /&gt;
*[[Layer]]s&lt;br /&gt;
*[[Building]]&lt;br /&gt;
*[[Line]]&lt;br /&gt;
*[[Stop]]&lt;br /&gt;
*[[Pax]]&lt;br /&gt;
*[[Train]]&lt;br /&gt;
*[[Run]]&lt;br /&gt;
*[[Order]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;column&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;strong&amp;gt;Guides&amp;lt;/strong&amp;gt;&lt;br /&gt;
*[[Quickstart guide]]&lt;br /&gt;
*[[How to use depots]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check out the [[Contents]] master page for work in progress overview of the current content of the wiki.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:NIMBY Rails Wiki]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=Main_Page&amp;diff=157</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=Main_Page&amp;diff=157"/>
		<updated>2022-12-09T16:29:36Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;style&amp;gt;&lt;br /&gt;
.row {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: row;&lt;br /&gt;
  flex-wrap: wrap;&lt;br /&gt;
  width: 100%;&lt;br /&gt;
}&lt;br /&gt;
.column {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: column;&lt;br /&gt;
  flex-basis: 100%;&lt;br /&gt;
  flex: 1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/style&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;wrapper&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Welcome to the NIMBY Rails wiki!&amp;lt;/strong&amp;gt;&lt;br /&gt;
This wiki is a &amp;lt;strong&amp;gt;work in progress&amp;lt;/strong&amp;gt;. You can help it to grow by creating an account and contributing guides, tips or extending the existing bare bones concept pages.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;column&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;strong&amp;gt;Basic concepts&amp;lt;/strong&amp;gt;&lt;br /&gt;
*[[Blueprint]]&lt;br /&gt;
*[[Track]]&lt;br /&gt;
*[[Station]]&lt;br /&gt;
*[[Signal]]&lt;br /&gt;
*[[Layer]]s&lt;br /&gt;
*[[Building]]&lt;br /&gt;
*[[Line]]&lt;br /&gt;
*[[Stop]]&lt;br /&gt;
*[[Pax]]&lt;br /&gt;
*[[Train]]&lt;br /&gt;
*[[Run]]&lt;br /&gt;
*[[Order]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;column&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;strong&amp;gt;Guides&amp;lt;/strong&amp;gt;&lt;br /&gt;
*[[Quickstart guide]]&lt;br /&gt;
*[[How to use depots]]&lt;br /&gt;
*[[How to signal a junction]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check out the [[Contents]] master page for work in progress overview of the current content of the wiki.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:NIMBY Rails Wiki]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=Main_Page&amp;diff=156</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=Main_Page&amp;diff=156"/>
		<updated>2022-12-09T16:29:03Z</updated>

		<summary type="html">&lt;p&gt;Admin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;style&amp;gt;&lt;br /&gt;
.row {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: row;&lt;br /&gt;
  flex-wrap: wrap;&lt;br /&gt;
  width: 100%;&lt;br /&gt;
}&lt;br /&gt;
.column {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: column;&lt;br /&gt;
  flex-basis: 100%;&lt;br /&gt;
  flex: 1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/style&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;wrapper&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;Welcome to the NIMBY Rails wiki!&amp;lt;/strong&amp;gt;&lt;br /&gt;
This wiki is a &amp;lt;strong&amp;gt;work in progress&amp;lt;/strong&amp;gt;. You can help it to grow by creating an account and contributing guides, tips or extending the existing bare bones concept pages.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;column&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;strong&amp;gt;Basic concepts&amp;lt;/strong&amp;gt;&lt;br /&gt;
*[[Blueprint]]&lt;br /&gt;
*[[Track]]&lt;br /&gt;
*[[Station]]&lt;br /&gt;
*[[Signal]]&lt;br /&gt;
*[[Layer]]s&lt;br /&gt;
*[[Building]]&lt;br /&gt;
*[[Line]]&lt;br /&gt;
*[[Stop]]&lt;br /&gt;
*[[Pax]]&lt;br /&gt;
*[[Train]]&lt;br /&gt;
*[[Run]]&lt;br /&gt;
*[[Order]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;column&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;strong&amp;gt;Guides&amp;lt;/strong&amp;gt;&lt;br /&gt;
*[[Quickstart guide]]&lt;br /&gt;
*[[How to us _depots]]&lt;br /&gt;
*[[How to signal a junction]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check out the [[Contents]] master page for work in progress overview of the current content of the wiki.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:NIMBY Rails Wiki]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://wiki.nimbyrails.com/index.php?title=Main_Page&amp;diff=123</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://wiki.nimbyrails.com/index.php?title=Main_Page&amp;diff=123"/>
		<updated>2022-12-07T15:06:51Z</updated>

		<summary type="html">&lt;p&gt;Admin: Protected &amp;quot;Main Page&amp;quot; ([Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite))&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;strong&amp;gt;Welcome to the NIMBY Rails wiki!&amp;lt;/strong&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Check out the [[:Category:Guide|guides]] and the [[:Category:Concepts|gameplay concepts]] of the game.&lt;br /&gt;
&lt;br /&gt;
[[Category:NIMBY Rails Wiki]]&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
</feed>