Every limit Asterobot sets on scripts, with its value and exactly what happens when a script goes past it.
Asterobot runs every script within fixed limits, so that one script can't hold up Asterobot or the other bots. They're the same for every bot and every package, and a package can't change them. None of them depends on the speed of the PC: a slower PC makes a script slower, never different. Here is each one, with its value and what happens past it.
Running code
| Limit | Value | Past the limit |
|---|---|---|
| Code running without a pause | 5 s | The script stops, and the Problems alert shows a text containing JavaScript execution deadline exceeded. The game connection stays open. |
| Function calls nested in each other | 1024 | The script stops. A try/catch can't catch this. |
The limit is there to stop code that never ends, such as an endless loop, and sits far above what a script's code takes. A pause is an await, or the end of the function Asterobot called. Each of these counts as one run, with its own 5 s:
- the top level of the modules, when the script starts;
- the entry function, up to its first
await; - one call of a handler: from
on(),onTraffic(),intercept(),onChange(),onStopRequest(),onFight(),onDecision(), a selector function, or an action'srun; - code resuming after an
await, together with any other code resuming at the same moment.
The text in the alert says which it was, for example Game traffic handler failed: JavaScript execution deadline exceeded for a handler, or drain JavaScript Promise jobs: JavaScript execution deadline exceeded for code that resumed after an await. The place in your code follows it.
Three cases don't stop the script:
- In an interceptor, the message goes on unchanged, and the bot's Console shows
interceptor failed: JavaScript execution deadline exceeded. - In a fight decision hook, the fight module's AI decides, and the bot's Console shows
fight decision hook failed: JavaScript execution deadline exceeded: the AI decides. - In an action's
run, the toast for the action says it failed, with the same text. - While Asterobot reads the package's declarations, reading fails. See Declarations.
Handlers, waits and sleeps
| Limit | Value | Past the limit |
|---|---|---|
Message handlers registered at once with on(), onTraffic(), intercept(), and asterobot:fight's onFight() and onDecision() together |
256 | The call throws a TypeError with maximum behavior handlers reached |
Handlers registered at once with onChange() |
256, counted apart from message handlers | The call throws a TypeError with maximum behavior handlers reached |
Handlers registered at once with onStopRequest() |
256, counted apart from the others | The call throws a TypeError with maximum behavior handlers reached |
wait() calls not settled yet |
128 | The new wait() rejects with behavior resource limit exceeded: maximum waits reached |
sleep() calls not settled yet |
128 | The new sleep() rejects with behavior resource limit exceeded: maximum timers reached |
A handler removed with off(), offChange() or offStopRequest(), and a wait or a sleep that settled, frees its place. A wait() without a timeout that never matches keeps its place until the script stops.
Pending operations
| Limit | Value | Past the limit |
|---|---|---|
Operations waiting for their result: request(), table(), find(), search(), query() and the asterobot:movement functions that return a promise, together |
32 | The new call's promise rejects with behavior resource limit exceeded: maximum pending operations reached |
send() doesn't count: it resolves as soon as its message is in line. text() and record() answer right away and don't count either. An operation frees its place when your code receives its result, so whether a script reaches the limit depends on what it does, never on how fast the answers come.
Events waiting for the script
| Limit | Value | Past the limit |
|---|---|---|
| Game messages waiting to be handled | 8 MB | The script stops with the script fell too far behind the game |
| Messages the script sent, waiting to be written | 8 MB | The new send() or request() rejects with behavior resource limit exceeded: more than 8 MB are waiting to be sent, so the connection isn't taking them |
The events are the messages that arrive, operations that finish, sleeps and wait timeouts that end, applied settings and clicked actions. A script handles them one at a time, in the order they came, so they pile up while its code is busy, for example in a handler that runs long or awaits nothing. Nothing is skipped: there's no limit on how many can wait, only on the size of the game messages waiting, and 8 MB means the PC can't keep up with the script at all. A MITM bot relaying a busy game session receives many messages each second: keep handlers short.
On a MITM bot, Asterobot never slows the game down for what watches it. When the Network tool can't keep up with the messages, Asterobot leaves some out of what it receives, and the game still gets them. A script never carries on with such a hole: it stops instead, with game traffic lost: Asterobot fell behind the game and missed messages. A Full socket bot waits instead, and misses nothing.
Timeouts
| Limit | Value | Past the limit |
|---|---|---|
send() |
None: it resolves as soon as its message is in line, and ignores { timeout } |
|
request() |
30 seconds from the call unless you pass { timeout } |
The promise rejects with context deadline exceeded |
wait() |
None unless you pass { timeout } |
With a timeout, the promise rejects with protocol wait timed out. Without one, it waits until the script stops. |
table(), find(), search() and query() |
None of their own: they end when their work is done | A query() is bounded by its own 10 seconds, see Game data |
| An interceptor's decision | None: the message waits for the script, however busy it is | An interceptor that runs for more than 5 s is stopped, like any code, and the message goes on unchanged |
Packages and modules
| Limit | Value | Past the limit |
|---|---|---|
| Modules the script loads, counting the built-in modules it imports | 256 | The script doesn't start: reachable module count exceeds limit 256 |
| Total size of those modules | 4 MiB (4,194,304 bytes) | The script doesn't start: reachable module source exceeds limit of 4194304 bytes |
Chain of imports, from index.js down |
64 modules | The script doesn't start: module graph depth <depth> exceeds limit 64 at "<module>" |
When a script doesn't start for one of these reasons, the toast after Play or Run doesn't say why. The bot's Settings tab does: Package settings shows Couldn't read this package's settings with the text.
Only the .js and .mjs files of a package are part of its code; its fight profiles, in fightprofiles/, and its chat profiles, in chatprofiles/, are its only data. A package archive you import is at most 32 MiB: see Zip files and the command line.
Game data
| Limit | Value | Past the limit |
|---|---|---|
Rows returned by one call of table(), find(), search() or query() |
200 by default, 5000 at most | A larger limit is lowered to 5000. query() sets truncated to true when rows were left out. |
Length of the SQL passed to query() |
65,536 bytes | The promise rejects with datacenter: query is <size> bytes, over the 65536 byte limit |
Time for one query(), once its turn has come |
10 seconds | The query is interrupted, and the promise rejects |
| Size of a single value a query builds | 16 MiB | The query fails |
| Queries running at once on one game version, across every bot and Asteroboard | 4 | The next query waits for its turn, in the order they came, for as long as it takes |
Bot memory
The bot's memory is shared by every package the bot runs, so these limits are for the whole bot, not for each package.
| Limit | Value | Past the limit |
|---|---|---|
| Length of a key | 256 bytes | memory.set() throws a TypeError with memory: a key must be a non-empty string of at most 256 bytes |
| Size of one value | 64 KiB | memory.set() throws an Error with memory: the value is larger than 64 KiB |
| Keys stored at once | 1024 | memory.set() of a new key throws an Error with memory: this bot's memory is full (1024 keys or 1 MiB) |
| Size of every value together | 1 MiB | memory.set() throws the same Error, unless the new value is no larger than the one it replaces |
| Levels of arrays and objects nested in a value | 32 | memory.set() throws a TypeError that says the value nests more than 32 levels deep |
A value's size is roughly the size of its JSON text, with every number counted as 8 bytes. memory.delete() frees what the key held.
Consoles
| Limit | Value | Past the limit |
|---|---|---|
| Lines Asterobot keeps for each bot's Console | 200 | A Console tab opened later starts with the last 200 lines only |
| Interceptor failures written to the bot's Console for one message | The first, and the tenth | When several interceptors fail on the same message, the other failures aren't written. The count starts again with each message. |
Error messages explains every text on this page, and Async and timing shows how to write scripts that stay within the limits.