WebAssembly

Limits

On this page

What bounds a plugin, and what happens when it reaches the bound. Every value here is a constant in the code cited beside it.

Fuel

A Wasm guest runs on fuel: a count of instructions per call. A guest that runs out traps, however deep in a loop it is, so a runaway guest is stopped rather than taking the tick with it. Fuel is refilled before every call. A native Rust plugin has no fuel: it is compiled into the server and trusted.

One ordinary call's fuel is 10,000,000 instructions. The server picks a budget for each call, as a multiple of that.

BudgetMultipleFuelGiven to
Normal×110,000,000events in the game loop, every hook (packets included), news on a topic
Large×20200,000,000command_run, server_started, server_stopping and settings_changed; calls from another plugin; menu clicks; the plugin's start
Extended×1001,000,000,000the handlers the manifest names in extended
Stop×5 by default50,000,000rustmc_stop. Set with plugins.stop-fuel-multiple in rustmc.yml

Fuel counts the guest's own instructions. The work a host call does on the server's side is not counted, but reading and writing the JSON of a call is the guest's own work, so a big answer costs fuel to parse. The guest SDK's host::calls_made() and host::bytes_received() let a plugin measure what it has asked for.

When a call fails

A call that traps, runs out of fuel or panics (a Rust plugin) is skipped. The plugin is not unloaded.

  • An event's failed handler counts as having passed, unless the manifest lists the event in fail_closed: then it counts as a cancel.
  • A hook's failed handler passes: the game's own step stands.
  • A plugin-bus call to a failed handler answers the caller with an error.
  • A trapped Wasm instance is thrown away and replaced with a fresh one of the same module, because a trap does not unwind and its memory may be half-changed. The fresh instance runs rustmc_start again (on the Large budget) before it is next asked anything, so it reads what the plugin saved. What the old instance held only in memory is lost.
  • A handler that fails 5 times in 1200 ticks (a minute) is paused for 1200 ticks. While paused it is answered as a failure, so a fail_closed event stays cancelled. The plugin's other handlers keep running.
  • A plugin whose start fails is not run at all, and /plugins shows it stopped.

Sizes and counts

LimitValueWhat happens past itSource
Bytes in one transfer, either way (an event, a hook call, a host call's answer)4 MiBcut to the limit and loggedrustmc-plugin-wasm/src/lib.rs:127, 604-613
A plugin-bus request2 MiBrefused with an errorrustmc-plugin-wasm/src/call.rs:1626-1630
Events a guest caused, waiting for its own call to return1024the newest is dropped and loggedrustmc-plugin-wasm/src/lib.rs:177, 840-854
Events, hooks and bus calls nested inside each other8 deepthe chain is stopped: the event passes (or fails closed if its plugin says so), the hook runs the game's own step, the bus call is refusedrustmc-server/src/plugins.rs:107-117, 486, 663, 854, 902
Wait for a guest busy on another thread, from inside another plugin250 msthe inner call is skipped and loggedrustmc-plugin-wasm/src/lib.rs:89-92
Blocks in one set_blocks, entries in one set_blocks_data4096errorrustmc-plugin/src/value.rs:519
Rows in one storage_put_many16,384errorrustmc-plugin/src/value.rs:529
Entities in one move_entities1024errorrustmc-plugin-wasm/src/call.rs:31
Entries in one tab-list, nametag or score batch1000errorrustmc-plugin/src/tab.rs:13
Viewers in one set_hidden4096errorrustmc-plugin-wasm/src/call.rs:43
entities_in radius128 blockserrorrustmc-plugin/src/value.rs:638
read_blocks box16 chunk columns; 512 KiB of block-entity dataerrorrustmc-plugin/src/value.rs:533-537
raycast distance512 blockserrorthe raycast doc comment
Chunk coordinates in a requestwithin 1,875,000 of the originerrorrustmc-plugin-wasm/src/call.rs:1866-1894
A plugin's name64 charactersnot loadedrustmc-server/src/plugins.rs:1169
A setting's text16,384 charactersrefusedrustmc-plugin/src/setting.rs:72

Each host call's own limits are in its doc comment on its reference page, with the router's error messages for its fields.

Concurrency

One call at a time per guest: a Wasm instance is one store behind one lock. A guest is never entered again while it runs on the same thread. Events it causes are queued until its call returns; a hook call or a bus message that would re-enter it is skipped and logged.

A Rust plugin's Plugin methods take &self and may be called from several threads at once. It keeps its own state behind its own lock.

From docs/api/wasm/limits.md in the RustMC repository at bbd81209ad.