Simutrans-Squirrel-API  r12240
Squirrel 3.2 runtime update

Table of Contents

English (canonical) | EspaƱol

Overview

Simutrans embeds the Squirrel language to run scripted scenarios and scripted AI players. The embedded Squirrel runtime has been updated to upstream Squirrel v3.2.

This is an update of the language runtime. It is not a redesign of the Simutrans Script API. Scripts do not need to be rewritten for it.

What changed

What did not change

Runtime provenance

The Squirrel sources shipped with Simutrans are a vendored copy of the upstream project at albertodemichelis/squirrel.

Previous vendored basis23a0620658714b996d20da3d4dd1a0dcf9b0bd98 a snapshot of the 3.1.x development line, dated 2021-09-16
New basisf92bc298784ceea459b12e2de33bdff672bfeb83 upstream release tag v3.2, dated 2022-02-10

The previous snapshot was taken from the development line after the 3.1 release, so it was neither an exact upstream 3.1 release nor a 3.2 one. Describing the update simply as "3.1 to 3.2" would therefore be inaccurate.

Compatibility

The two scripted AI players shipped with Simutrans, sqai and sqai_rail, were run against the new runtime and remained compatible. In the tested campaign they preserved their logical connection state, continued making valid progress and produced no script or runtime errors. Some scheduling and route-search choices may differ because of table iteration order, as described below. Loading a savegame written by the previous runtime was also tested and works.

This is a statement about the scripts and paths that were covered by that test campaign. It is not a guarantee that every possible script is unaffected. A script that depends on table iteration order may behave differently - see the next section.

Table iteration order

Warning
Do not rely on the iteration order of Squirrel tables unless it is explicitly documented by the API.

Squirrel 3.2 changes the hash function used for string keys. Tables are hash containers, so this changes the order in which foreach visits their entries.

The consequence for a script is indirect but real. If a script iterates a table to pick the next thing to work on, the new order may change:

This is not corruption and it is not randomness. For the same input the runtime behaves the same way every time, the script keeps its complete logical state, and execution stays valid. What changes is a tie-break that was never guaranteed in the first place.

If a script needs a defined order, it must impose one - for example by collecting the keys into an array and sorting it - rather than relying on the order a table happens to produce.

Arrays are not affected: they are ordered containers and their order is part of their contract.

Savegame compatibility

Savegames written by the previous runtime load correctly under Squirrel 3.2. This was tested with the scripted AI players shipped with Simutrans. The same old-runtime save was loaded repeatedly to confirm reproducibility. A state loaded under 3.2 was also saved again and reloaded successfully. The scripts resumed with their persistent state complete.

The reverse direction - loading a savegame written by Squirrel 3.2 into an older Simutrans build - was not part of this work and is not claimed.

When a script's persistent state is written out again, the entries of a saved table may appear in a different order than before. The saved state itself is unaffected: it is restored by name, not by position.

bindenv

Binding an environment to a function is a feature of the Squirrel language, not a Simutrans class or API registration.

The existing method is unchanged and continues to work:

local env = { factor = 2 }
local scale = function(x) { return x * factor }
local bound = scale.bindenv(env) // 'this' inside scale is now env
bound(21) // 42

Squirrel 3.2 adds an inline form. The environment is written in square brackets between the function name and the parameter list:

local env = { factor = 2 }
local scale = function [env] (x) { return x * factor }
scale(21) // 42

The same bracket form is accepted for named functions, for local functions and for class and table members, including constructor.

Both forms produce a closure whose environment is the given table, class or instance. The inline form is a convenience; it does not give access to anything the method form did not already allow. Existing scripts need no change.

table.map

Squirrel 3.2 adds a map method to tables in the standard library. Arrays already had one.

The callback is called once per entry and receives the key and the value, with this bound to the table:

local prices = { coal = 10, oil = 25 }
local labels = prices.map(function(key, value) {
return key + "=" + value
})

Two properties are worth knowing:

Notes for AI and scenario authors

Known scope limits

Further reference