Builds, limits and errors
validate_code and commit build the game and run its unit tests. This section lists what a build accepts, the errors it answers, the limits of a test run, and the limits of a match.
Source files
- The crate root is
/src/lib.rs. Without it the build fails withbw::no-crate-root. - Every other Rust file is a module the crate declares with
mod name;:/src/cards.rsformod cards;,/src/cards/deck.rsformod deck;insidecards. A file nomodreaches is warningbw::unused-file. - Paths use lowercase letters, digits and
_, start with a letter or_, end in.rs, and are at most 8 directories deep. - JSON the game logic reads goes in
/src/data/. See Data files. - At most 200 files, 256 KiB per file and 2 MiB in total, data files included.
write_file, patch_file and rename_file refuse a .rs path, a data file path or a size the build can never accept, with UNBUILDABLE_RUST_SOURCE.
Crates
A game may use exactly three crates: boardweaver_sdk, serde and serde_json. They are already in scope by name. Use serde's derive through the SDK:
use boardweaver_sdk::serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
#[serde(crate = "boardweaver_sdk::serde")]
struct Hand {
cards: Vec<String>,
}
There is no Cargo.toml to edit. Write Rust 1.98.1, edition 2024.
Words the build refuses
The build refuses these words anywhere in a .rs file, tests included, even as your own names:
| Refused | Write instead |
|---|---|
static, thread_local |
Keep the value in the state, or make it a const. |
unsafe |
Safe Rust. The SDK gives a game everything it needs. |
extern |
Nothing: the three crates are already in scope. |
env, option_env |
Another name, such as environment. |
include, include_str, include_bytes |
A data file read with data!, a const in the source, or a module file with mod. |
asm, global_asm, naked_asm |
Rust. |
Also refused: mod inside a macro, #[path], #[should_panic], crate-level #![...] attributes other than allow, warn, deny, forbid, expect and doc, and brackets nested deeper than 256. The 'static lifetime is allowed.
Reading a build error
validate_code answers errors and warnings as text in the Rust compiler's format, with paths as you wrote them:
error[bw::refused]: a game may not declare a `static`
--> /src/lib.rs:12:1
|
12 | static COUNT: u32 = 0;
| ^^^^^^
= help: A game is a pure function of its state, the action and the seed, so nothing may outlive a call. Keep the value in a field of the match's state, or use a `const` or a function; for a lookup table, build a `BTreeMap` where you need it rather than caching it
Every bw::refused error ends with a help line that says what to write instead.
A failed commit answers BUILD_FAILED with the first 20 errors. Fix them from the top: later errors often follow from the first.
| Code | Means |
|---|---|
E...., a lint name |
the Rust compiler's own error or warning |
bw::refused |
a refused word, above |
bw::lex |
a file does not read as Rust tokens |
bw::no-crate-root |
no /src/lib.rs |
bw::unused-file |
a file no mod reaches (warning) |
bw::read-outside-source |
the code refers to a file outside the game's .rs and data files |
bw::data-json |
a data file is not JSON (Data files) |
bw::module-too-large |
the built game is over 4 MiB |
bw::bad-module |
the built game exports no game: check for export_game! |
bw::test-failed |
a unit test panicked or returned an Err; the error points at the panic's line and quotes its message (Testing a game) |
bw::test-fuel |
a unit test used all its computation, or the tests used all of theirs and the rest did not finish, below |
bw::test-trap |
a unit test stopped another way, such as running out of memory, or the tests ran out of time, below |
bw::too-many-tests |
the game logic has more than 200 unit tests, or their names are over 256 KiB, so none ran |
bw::client-types |
the types listed in client_types! do not read, or their JSON Schema is over 512 KiB; the message names the problem, such as two types sharing one name or a type that refers to one no client_types! defines (Client types) |
bw::time-limit |
the build ran past its time limit |
bw::memory-limit |
the build ran out of memory |
bw::truncated |
more than 200 diagnostics; only the first are shown |
Tool errors
| Code | Tool | Means |
|---|---|---|
GAME_NOT_FOUND |
every tool whose input requires gameDefinitionId, and save_checkpoint |
The game does not exist, was deleted, or your role on it does not reach the tool. Boardweaver gives all three the same answer. |
UNBUILDABLE_RUST_SOURCE |
write_file, patch_file, rename_file |
A .rs path, a data file path or a size the build cannot accept. |
BUILD_FAILED |
commit, start_game |
The game logic did not build, a unit test failed, or a client type's name cannot be exported from boardweaver/game (Client types). For commit only, the client did not build. |
BUILD_BUSY |
validate_code, commit, start_game |
Boardweaver is building other games. Try again after the time it names. |
BUILD_UNAVAILABLE |
validate_code, commit, start_game |
Boardweaver cannot build games right now. Try again later. |
NOT_CONFIGURED |
validate_code, commit, start_game |
This Boardweaver environment cannot build games. |
TYPE_CHECK_BUSY |
validate_code |
Boardweaver is type-checking other games. Nothing changed. Try again in a moment. |
INVALID_STATE |
start_game, set_state |
The state is not one a session can hold. The message names each problem. |
INVALID_ACTION |
apply_action |
The action is not a v3 action. Copy one offer's action. |
ACTION_REFUSED |
apply_action |
Boardweaver or the game refused a step, for the reason the message gives. Nothing changed. |
DECISION_IN_PROGRESS |
apply_action |
Another player has an open decision. End it, or drop it with set_state. |
INIT_FAILED, APPLY_FAILED, REFRESH_FAILED |
start_game, apply_action, set_state |
The game logic failed, for example with a panic or a timeout. The message has what the game printed. |
GAME_RUNNER_UNAVAILABLE |
start_game, apply_action, set_state |
Boardweaver cannot reach its game runner. Nothing changed. Try again in a minute. |
GAME_RUNNER_BUSY |
start_game, apply_action, set_state |
Boardweaver's game runner is busy with other games. Nothing changed. Try again in a moment. |
SESSION_CHANGED |
apply_action, set_state |
Another call changed the session while this one ran, so this call changed nothing. Read it with inspect_state, then try again. |
RENDER_UNSUPPORTED |
render_game |
The session has no client to render: it did not build, or the game has none. start_game's warnings says which. |
UNSUPPORTED_ON_THIS_VERSION |
save_checkpoint, start_game, set_state |
The tool does not take a v3 session, or start_game or set_state was given validateTypes. |
Test limits
Every build runs the unit tests with these limits:
| Limit | Value | When it is hit |
|---|---|---|
| Tests | 200, with names of at most 256 KiB in all | bw::too-many-tests, and no test runs |
| Computation per test | 10,000,000,000 units, enough for play_bots to play a game |
bw::test-fuel |
| Computation for all the tests | 40,000,000,000 units | bw::test-fuel, and the rest do not finish |
| Memory per test | 50 MiB, as in a match | bw::test-trap |
| Time | the whole build, tests included, ends 140 seconds after it starts | bw::test-trap, and the rest do not run |
Limits in a match
Each call to a game function has these limits:
| Limit | Value | When it is hit |
|---|---|---|
| Memory | 50 MiB | GAME_FAILED |
| Computation | a fixed budget per call, which a long loop or a deep search can use up | EXECUTION_TIMEOUT |
| Time | about 4 seconds per call | EXECUTION_TIMEOUT |
| State | 1 MiB as JSON | GAME_FAILED |
| The offers and changes of one call | 2 MiB as JSON | GAME_FAILED |
| Log lines of one step, or of the opening | 32 lines, 32 segments per line, and 8 KiB as JSON for all of them | GAME_FAILED: table.log panics |
A panic in the game logic is GAME_FAILED, with the panic message and any text the game logic printed. Each failure is recorded as a match error, which the game's studio lists.