The [script] manifest
Every key of the [script] section of neo.toml, its type, default and meaning, and the errors NEO reports for a bad manifest.
The [script] section of a game's neo.toml is its script manifest. It names the game's script language and scripts, sets the budgets, says what the game's own scripts may touch, and controls live scripting by players. A game without a [script] section runs no scripts and exposes nothing.
[script]
language = "js"
scripts = ["assets/scripts/platform.js"]
fuel_per_tick = 1_000_000
fuel_per_call = 500_000
calls_per_tick = 2_000
memory = "16MB"
[script.expose.Platform]
fields = { position = "get set", speed = "get", label = "get", display_name = "get" }
methods = ["boost"]
[script.expose.Player]
fields = { position = "get", name = "get" }
[script.expose.Cube]
fields = { position = "get set", size = "get set" }
spawn = true
[script.players]
allowed = "nobody"
fuel_per_tick = 100_000
calls_per_tick = 100
memory = "4MB"
[script.roles.player]
grant = ["Platform.position:get", "Player.position:get"]
[script.roles.builder]
grant = ["Cube:spawn", "Cube.position:set", "Cube.size:set", "Platform.boost:call"]
[script.roles.admin]
grant = ["Platform.display_name:get set"]Every grant is checked against what the game's Rust types declare with #[derive(ScriptExpose)] (see Exposure and permissions). The manifest can narrow what Rust declares, never widen it.
[script]#
| Key | Type | Default | Meaning |
|---|---|---|---|
language | string | "js" | The game's one script language: "js" (or "javascript") or "py" (or "python"). |
scripts | list of strings | [] | The game's own scripts, as paths relative to the project. They load in this order, as the game's scripts. |
fuel_per_tick | integer | 2_000_000 | Instructions each script may use per tick, across all its calls. |
fuel_per_call | integer | 1_000_000 | Instructions for one call into a script (one event, or the tick). |
calls_per_tick | integer | 10_000 | World calls each script may make per tick. |
memory | integer or string | "64MB" | Memory per script: a number of bytes, or a string with a unit (B, K/KB, M/MB, G/GB; for example "16MB"). |
expose | table | none | [script.expose.<Kind>] sections (below). |
players | table | none | The [script.players] section (below). |
roles | table | none | [script.roles.<role>] sections (below). |
A script's name is its file name without the extension (assets/scripts/platform.js runs as platform). Sizes use powers of 1,024: "16MB" is 16 × 1,048,576 bytes. The budgets are explained in Limits and determinism.
[script.expose.Kind]#
What the game's own scripts may do with one kind. Kind stands for the kind name as declared in Rust (kind = "Platform"). A kind with no section doesn't exist for the game's scripts.
| Key | Type | Default | Meaning |
|---|---|---|---|
fields | inline table | none | Field name to access: "get", "set" or "get set" ("read" and "write" also work). Use the snake_case names. position is the entity's transform, if the type declares one. |
methods | list of strings | none | Methods the scripts may call. |
spawn | boolean | false | Whether the scripts may create this kind with spawn. |
[script.expose.Door]
fields = { open = "get" }
methods = ["open"][script.players]#
Live scripting by players: scripts a player loads into a running session.
| Key | Type | Default | Meaning |
|---|---|---|---|
allowed | string | "nobody" | Who may load live scripts (values below). |
fuel_per_tick | integer | 200_000 | Per-tick instructions for each player script. |
fuel_per_call | integer | 200_000 | Per-call instructions for each player script. |
calls_per_tick | integer | 200 | World calls per tick for each player script. |
memory | integer or string | "4MB" | Memory per player script. |
Values of allowed:
| Value | Who may load live scripts |
|---|---|
"nobody" | No one. |
"owner" | The game's owner. |
"friends" | The owner and the owner's friends. |
"role:<name>" | The owner and players holding the role <name>. |
"everyone" | Every player. |
The player budgets are the same for every player and device. A player's script also has to pass the game's moderation check (by default, sources over 64 KB are refused).
[script.roles.role]#
Grants for players holding a role; role stands for the role's name. Every player holds the role player, so [script.roles.player] is what all player scripts get. A player's scripts get the player grants plus those of every other role they hold, and start with nothing else.
| Key | Type | Default | Meaning |
|---|---|---|---|
grant | list of strings | required | The role's grants (forms below). |
| Grant | Allows |
|---|---|
"Kind.field:get" | Reading the field. |
"Kind.field:set" | Writing the field. |
"Kind.field:get set" | Both (a comma also works: "get,set"). |
"Kind.method:call" | Calling the method. |
"Kind:spawn" | Spawning the kind. |
Fields and methods that Rust restricts to roles (roles = [...] in the derive) are removed for players who hold none of those roles, whatever the grants say. The game's own scripts aren't affected by role restrictions.
Errors#
A manifest with a problem doesn't half-work. NEO reports one of these, prefixed with neo.toml [script] and the key it's about:
| Problem | Message |
|---|---|
language isn't a known language | one of "js" or "py" (one language per game) |
A languages key (more than one language) | a game packages one language: use language = "js" |
scripts isn't a list of strings | a list of paths / paths are strings |
| A budget isn't a non-negative integer | expected a non-negative integer |
A bad memory value | a size is a number of bytes or a string like "16MB", unknown size unit, or ... isn't a size |
An unknown key in [script] | unknown key |
An unknown key in [script.expose.<Kind>] | unknown key (fields, methods, spawn) |
| A bad access string | access is "get", "set" or "get set" (or empty access) |
spawn isn't a boolean | spawn = true | false |
A bad allowed value | "nobody", "owner", "friends", "role:<name>" or "everyone" |
A role without a grant list | a list of grants |
| A grant in the wrong form | expected Kind.name:access, or only Kind:spawn names a kind alone |
These errors are checked against the game's Rust declarations:
| Problem | Message |
|---|---|
| A kind no Rust type registers | `Platfrom` isn't a script kind (no #[derive(ScriptExpose)] registers it) |
| A field Rust doesn't declare | `Platform.speedd` isn't declared for scripts |
| More access than Rust declares | `Player.position` grants more than the type declares |
| A method Rust doesn't declare | `Platform.bost` isn't a declared script method |
What happens when there's a problem:
- The section can't be read (a syntax or type error): the game logs
manifest refused: ...and runs with no scripts exposed. - A grant doesn't match the declarations: a script that would run under those grants is refused, and the load log says why. The game's other parts keep running.
The Scripts panel's check validates the whole manifest against the declarations and lists every problem at once. See The Scripts panel.