SplitScript reference / Migration

Migration

Choose the source language first, then the task or source concept. Stable catalog identities remain searchable, but the navigation follows the way a porter approaches the work.

ASL

For lifecycle and semantic context, start with the complete ASL porting guide.

Attachment and state

  • Assignments to current: Assign directly to current.field for an explicit post-read override; old remains read-only. Use a trailing state-field if when rejection must happen at the transactional acceptance boundary, including the first snapshot. Supported directly

  • Attachment state declaration: Declare one native process name, an array of alternate process names, or a typed emulator provider per autosplitter file. An ASL declaration listing multiple processes becomes alternate names for one attachment, not concurrent attachments. Names are exact host identities, so Windows executable candidates currently include .exe. The declaration owns attachment and defines the fields polled into old and current. Use a typed pattern

  • Attempt-scoped and run-scoped variables: Declare a bare top-level let and assign it on every completing onStart path. The inferred attempt-scoped value remains available across process detach and is cleared after onReset, replacing manually reset run-owned state in polling code. Supported directly

  • Bounded native stringN state: Choose the native encoding explicitly: utf8 bounds bytes and utf16le bounds two-byte code units. Use a typed pattern

  • Contiguous memory aggregates: Read physically contiguous values as one naturally aligned record or fixed-length [T; N] array when that type exactly matches the target-memory layout. Use a typed pattern

  • MemoryWatcher: Declare polled memory in state; use a trailing field if with value and return Err(message) when a transient candidate should retain its last accepted value. Use a typed pattern

  • MemoryWatcherList: Use state for a fixed set of named transactional reads or retain runtime-discovered homogeneous addresses in an array; managed collection enumeration remains a distinct provider requirement. Use a typed pattern

  • State snapshots in helper functions: Helpers may read old and current directly or accept caller-selected snapshots as inferred parameters. The compiler propagates direct snapshot requirements and rejects calls before committed snapshots exist. Supported directly

  • Version-labelled state blocks: Use named layouts in one state block and return the selected layout from onAttach. Use a typed pattern

Process and memory

  • Attached process identity: Use process.name() to read the exact process candidate that matched during attachment; use module metadata when the executable name alone does not identify a build. Supported directly

  • Background signature scans: Remove legacy worker threads and await a module, explicit-range, or process-wide scan. Scans inspect a bounded window per tick and process closure cancels pending discovery. Use a typed pattern

  • DeepPointer: Use typed state paths for polled fields or process.follow for discovered paths. Supported directly

  • Loaded module discovery: Replace the enumerable ASL module bag with the narrow typed probe that matches the source intent: main executable discovery, a known optional module, a required module, or typed build identity. Preserve genuine unknown-name enumeration as an explicit host-runtime gap. Use a typed pattern

  • Task.Run: Replace worker threads with cooperative await discovery or a bounded retry transaction so timer updates keep yielding predictably. Use a typed pattern

Lifecycle and timer

Settings

  • Dynamic settings lookup: Replace settings[key] with settings.enabled(key) and settings.ContainsKey(key) with settings.contains(key). Declare exact host strings with key "..."; choice and file settings remain statically typed. Supported directly

  • Finite startup-generated settings: Use a compile-time settings family for bounded integer-keyed booleans; it lowers to ordinary declarations and remains available through settings.enabled(key). Supported directly

  • Runtime settings registration: Move settings.Add calls into the static settings declaration, preserving the display label, stable host key, default, hierarchy, and tooltip explicitly. A bounded settings.Add loop becomes a compile-time settings family instead of hand-expanded declarations. Use a typed pattern

Collections and text

  • Bounded integer ranges: Use ..< for an exclusive upper endpoint or ..= for an inclusive one; SplitScript rejects bare .. so the endpoint policy is explicit. Supported directly

  • List collections: Use [T] for C# ordered list semantics; size-changing operations belong on variable-length arrays, while [T; N] remains fixed and no separate List type is planned. Use a typed pattern

Unity and emulators

  • GameCube emulator attachment and memory mapping: Use GCN for Dolphin and the supported RetroArch Dolphin core. The provider owns emulator discovery, address translation, and big-endian decoding, so gcn reads original GameCube addresses without manual byte swapping. Supported directly

  • GBA emulator attachment and memory mapping: Use GBA for VisualBoyAdvance or VBA-M, mGBA, NO$GBA, Mednafen, supported RetroArch cores, and mGBA-based BizHawk. The provider owns emulator discovery and the gba root reads original EWRAM and IWRAM addresses without manual DeepPointer mappings. Supported directly

  • Genesis emulator attachment and memory mapping: Use Genesis for Fusion, Gens, BlastEm, Sega Game Room or Genesis Classics, and supported RetroArch cores. The provider owns discovery, normalizes emulator storage and byte order, and reads original work-RAM offsets through genesis. Supported directly

  • Master System and Game Gear emulator attachment: Use SMS for Fusion, BlastEm, Mednafen, and supported RetroArch Master System or Game Gear cores. The provider owns emulator discovery and the sms root reads original work-RAM addresses. Supported directly

  • PlayStation 2 emulator attachment and memory mapping: Use PS2 for PCSX2 and the supported RetroArch PCSX2 core. The provider owns emulator discovery and the ps2 root reads original PlayStation 2 addresses without manual host-memory mappings. Supported directly

  • PlayStation emulator attachment and memory mapping: Use PS1 for ePSXe, pSX, DuckStation, Mednafen, PCSX-Redux, XEBRA, and supported RetroArch cores. The provider owns emulator discovery and the ps1 root reads original PlayStation addresses. Supported directly

  • UnityASL, mono.Make, and managed metadata: Use the Unity state provider with top-level image, namespace, and class schemas instead of manually discovering Mono or IL2CPP metadata with UnityASL, mono.Make<T>, or mono.MakeString. Supported directly

  • Wii emulator attachment and memory mapping: Use Wii for Dolphin and the supported RetroArch Dolphin core. The provider owns emulator discovery, MEM1 and MEM2 translation, and big-endian decoding, so wii reads original Wii addresses without manual byte swapping. Supported directly

Unsupported host behavior

  • LiveSplit current game time: Keep script-computed game time as a typed Duration; reading the host's coherent optional game-time snapshot requires additional runtime support. Planned

  • LiveSplit current real time: Use Instant only for independent elapsed-time checks; exact timer.CurrentTime.RealTime metadata requires additional host support. Planned

  • LiveSplit run and segment metadata: Current segment identity, route length, category/game names, and splits-file metadata require a typed read-only host snapshot. Planned

  • LiveSplit timer configuration: Run-offset and timing-method access needs an ordered least-privilege host contract; ports must not silently omit these user-visible mutations. Planned

  • shutdown lifecycle block: Exact script teardown needs the planned host shutdown notification; onDetach is not equivalent. Planned

  • split timer event handler: Exact onSplit delivery still needs an ordered host event contract that can distinguish splits, skips, and undos between updates. Planned

C#

  • Array length: Call values.length() for the u32 element count of dynamic and fixed arrays. Supported directly

  • ASCII string lowercasing: Use toAsciiLowerCase when game identifiers require ASCII-only normalization; this is not culture-sensitive Unicode lowercasing. Supported directly

  • ASCII string uppercasing: Use toAsciiUpperCase when game identifiers require ASCII-only normalization; this is not culture-sensitive Unicode uppercasing. Supported directly

  • ASCII whitespace trimming: Use trimAsciiWhitespace for text known to use ASCII boundary whitespace; review Unicode and character-set trimming explicitly. Use a typed pattern

  • Bitwise complement: Use type-directed !: it is logical negation for booleans and width-preserving bitwise complement for integers. Supported directly

  • Boolean conversion: Use value != 0 for numbers, the value itself for bool, and explicit trimmed ASCII-insensitive true/false handling for strings. Use a typed pattern

  • Bulk array extension: Call values.extend(moreValues) to append a typed array in order; extending an array with itself duplicates its original contents once. Supported directly

  • C# duration ticks: Convert 100-nanosecond C# ticks to a source unit explicitly, with range review; SplitScript does not expose C# ticks as a native duration unit. Use a typed pattern

  • Collection count: After choosing an array or set from the source's ordering and uniqueness requirements, call values.length() for its u32 count. Supported directly

  • Display conversion: Use value as String for ordinary Display conversion and integer.toString(radix) for bases 2 through 36; culture, null, and object overloads require separate policies. Use a typed pattern

  • Exact string replacement: Use fallible replaceAll for immutable exact replacement; explicitly handle failure and translate a null C# replacement to an empty string only when deletion was intended. Use a typed pattern

  • Fixed-width numeric types: Memory-facing numbers use explicit signedness and bit widths. Supported directly

  • Floating-point ceiling: Use value.ceil() with an explicit f32 or f64 boundary; review C# decimal inputs separately. Use a typed pattern

  • Floating-point conversion: Use an explicit f32/f64 as cast for numbers, String.parse for text, or an if expression for booleans. Use a typed pattern

  • Floating-point floor: Use value.floor() with an explicit f32 or f64 boundary; review C# decimal inputs separately. Use a typed pattern

  • Floating-point rounding: Use value.round() or value.roundTo(digits) for midpoint-to-even floating-point rounding; review result width, decimal inputs, and explicit midpoint modes. Use a typed pattern

  • Floating-point square root: Use value.sqrt() with an explicit f32 or f64 boundary when preserving C# Math versus MathF semantics. Use a typed pattern

  • Floating-point truncation: Use value.truncate() with an explicit f32 or f64 boundary when preserving C# Math versus MathF semantics. Use a typed pattern

  • Function declarations: Functions and methods use the fn declaration keyword. Supported directly

  • Integer conversion: Choose fixed-width as, midpoint-to-even rounding, strict string parsing, or an explicit boolean mapping from the source type; C# checked overflow is not SplitScript cast behavior. Use a typed pattern

  • Last substring position: Use lastIndexOf for an optional final UTF-8 byte offset; review C# UTF-16 index arithmetic and replace the -1 sentinel with T? handling. Use a typed pattern

  • Nullable blank strings: Use String.isBlank for required strings and match String? explicitly when absence should also count as blank. Use a typed pattern

  • Nullable string emptiness: Use String.isEmpty for required strings and match String? explicitly when absence should also count as empty. Use a typed pattern

  • Numeric maximum: Use left.max(right) after establishing one intended numeric type; review C# implicit conversions and decimal overloads. Use a typed pattern

  • Numeric minimum: Use left.min(right) after establishing one intended numeric type; review C# implicit conversions and decimal overloads. Use a typed pattern

  • Numeric powers: Use value.squared() for the corpus-proven exponent two and an explicit typed shift for power-of-two masks; general floating powers remain planned. Use a typed pattern

  • Numeric string parsing: Replace static Parse/TryParse calls and output parameters with fallible text.parse() and ordinary T! handling. Supported directly

  • Signed absolute value: Use value.abs() after establishing a signed numeric type; review C# signed-minimum overflow, unsigned conversions, and decimal inputs. Use a typed pattern

  • String collection joining: Use String.join(values, separator) for a typed string array; convert C# object, variadic, enumerable, and range overloads explicitly. Use a typed pattern

  • String equality: Use == or != for exact string content equality; use equalsIgnoreAsciiCase only when ASCII-insensitive matching is intended. Supported directly

  • String length: Use isEmpty() for emptiness and byteLength() only for UTF-8 byte-oriented or proven ASCII logic; C# Length counts UTF-16 code units. Use a typed pattern

  • String padding: Use padStart(width, fill) or padEnd(width, fill) with an explicit character; review C# UTF-16 widths against SplitScript's Unicode-scalar widths. Use a typed pattern

  • String type: The immutable UTF-8 string type is named String. Supported directly

  • Substring extraction: Use fallible slice(start, exclusiveEnd) only after translating C#'s length argument and verifying that UTF-16 source positions are valid UTF-8 byte offsets. Use a typed pattern

  • Substring position: Use indexOf for an optional UTF-8 byte offset; review C# UTF-16 index arithmetic and replace the -1 sentinel with T? handling. Use a typed pattern

  • Text duration parsing: Replace TimeSpan.Parse according to whether the input is fixed data or an already-typed timer value; do not preserve culture-sensitive parsing by default. Use a typed pattern

  • Timer durations: Use Duration instead of C#'s TimeSpan. Supported directly

  • Variable declarations: Use one inferred let declaration; SplitScript has no const/let split. Supported directly

JavaScript

  • Absent optional values: None is SplitScript's zero-sized unit value and the absent side of an option. Supported directly

  • Strict equality operators: Use typed == and !=; SplitScript has no coercing equality operators, so JavaScript's extra = is unnecessary. Supported directly

Rust

  • Numeric byte order: Use Numeric.swapBytes to reverse a numeric value's raw bytes after reading data stored in the opposite byte order. It preserves the exact integer or floating-point type; eight-bit values are unchanged. Supported directly