SplitScript reference / Decision guides
SplitScript decision guides
Use these short guides when the question is which language form owns a task. Open the linked language or standard-library symbol afterward for exact syntax, examples, and effects.
Choose a lifecycle block
| Action | Timing | Available context | Suspension | Result | Fallthrough |
|---|---|---|---|---|---|
| setup | Once, when the loaded module first updates | settings and initialized module globals | not allowed | None | complete setup |
| onStart | After an observed timer transition out of NotRunning | settings, module globals, and globals initialized here | not allowed | None | complete the event |
| onReset | After an observed timer transition into NotRunning | settings, module globals, and attempt globals | not allowed | None | complete, then clear attempt globals |
| onAttach | Once after acquiring and preparing a process | process, prepared provider roots, settings, and globals; layout when already selected | await and retry allowed; cancelled on detach | None, Layout, or StateLayout as required by state | finish attachment when no layout result is required |
| onStateReady | Once after the first complete state snapshot | process, provider roots, layout, globals, old, and current | not allowed | None | complete initialization |
| whileAttached | Every initialized attached update after state refresh | process, provider roots, layout, globals, old, and current | not allowed | bool | true; continue to timer decisions |
| start | After whileAttached when the sampled timer is NotRunning | process, provider roots, layout, globals, old, and current | not allowed | bool | false; do not start |
| isLoading | After start handling when the sampled timer is Running or Paused | process, provider roots, layout, globals, old, and current | not allowed | bool? | None; retain the current loading state |
| gameTime | After isLoading when the sampled timer is Running or Paused | process, provider roots, layout, globals, old, and current | not allowed | Duration? | None; retain the current game time |
| reset | After loading and game-time updates when the sampled timer is Running or Paused | process, provider roots, layout, globals, old, and current | not allowed | bool | false; continue to split |
| split | After reset declines when the sampled timer is Running or Paused | process, provider roots, layout, globals, old, and current | not allowed | bool | false; do not split |
| onDetach | Once after an attached process closes and its context is cleared | settings, module globals, and live attempt globals | not allowed | None | complete cleanup |
Use onAttach for cooperative process discovery, then onStateReady when
initialization needs the first committed old and current snapshots.
Use whileAttached only for per-update bookkeeping that should run before
the timer decisions. onStart and onReset observe timer transitions even
while detached, so they cannot use process or snapshot context.
Choose a state field form
- Use an
atfield when polling follows a fixed module-relative, absolute, or sibling-field pointer path. - Use an expression-backed
statefield when attachment discovery supplies an address, several local steps compute one value, or ordinary API calls read the value. - Keep the field as
Twhen a failed read should retain its last accepted value. UseT?only when absence itself should entercurrentandold. - Put values in one record or fixed array when they must succeed and advance as one transaction.
- Use independent
layoutdimensions for independent build facts. Use named layouts when each build selects one complete alternative memory shape.
Choose absence, failure, retrying, or waiting
T?represents expected absence. Match it or useelsewhen a default is appropriate.T!preserves an error. Use postfix?to transfer it to the nearest fallible function, state field, orretryboundary.- Use
elsefor one local fallback that should happen immediately. - Use
retryfor bounded synchronous work that should be evaluated again from the beginning on a later attached update. - Use
awaitfor one existingasync Toperation that owns its polling progress. Constructing the future does no work; polling it makes progress.
Do not put await inside retry. Await asynchronous discovery first, then
retry a synchronous transaction if the resulting reads can still fail.
Choose the correct string unit
Stringstores immutable UTF-8 text. Equality compares text, not a host language's indexing unit.byteLength,byteAt, andsliceuse UTF-8 byte offsets. A character may occupy several bytes.charAtreads the Unicode scalar value beginning at a proven UTF-8 character boundary; the supplied index is still a byte offset.- Native state-field
utf8bounds bytes and rejects invalid UTF-8. - Native state-field
utf16lebounds two-byte UTF-16 code units and replaces unpaired surrogates while decoding. - Managed
Stringfields usemaxLengthmeasured in UTF-16 code units. This is an allocation/read bound, not a distinct string type.
When porting C# index arithmetic, first decide whether the source position is a UTF-16 code-unit index, a Unicode-scalar index, or a byte offset. Do not carry the number across unchanged until that unit is proven equivalent.