Skip to content

Run event and event argument scripts on Luau - #135

Open
carrdylan52 wants to merge 6 commits into
TheMoonPeople:masterfrom
carrdylan52:pr/luau-m4-events
Open

carrdylan52 wants to merge 6 commits into
TheMoonPeople:masterfrom
carrdylan52:pr/luau-m4-events

Conversation

@carrdylan52

@carrdylan52 carrdylan52 commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Event and event argument scripts currently run on the bytecode interpreter. This change runs 938 of the 974 published scripts of those kinds on Luau, including event skipping. The remaining 36 stay on the interpreter through the enforced fallback list.

The translator models skip execution in bytecode order, including ignored branches, retained conditions, calls, waits, SKIP_END and stack overflow. The event catalogue and bindings preserve the tags handlers inspect, distinguish input values from output references, and support outputs written after a menu closes. The harness adds skip scenarios, event flags and party state, native argument tag checks, and retail print formatting.

The series keeps handwritten changes separate from one generation from data v20: catalogue and declarations; harness; translation and regressions; generated modules; runtime enablement and tests; documentation and the prologue input. It adds no third-party dependency and changes no PS2 source. The generated map modules and shared event helpers occupy about 54.7 MB of source.

Validation at f4b673f:

  • Event and event argument corpus, 32 seeds: 2,701,952 scenarios pass, zero failures, 80.3% mean compared coverage. The registered four-seed Luau.TranspileEvent gate passes 337,744 scenarios and has a 3600-second timeout.
  • Action, effect and monster corpus, 32 seeds: 120,274 pass, 232 compared prefixes and 70 unsupported scenarios, zero failures. All 3,074 reached mutations in the CTest sample are rejected.
  • The Python suite reports 355 tests, OK, with the optional full-corpus timing test skipped. Native Luau runtime tests pass; native probes verify event argument tags and exclusion of stale fallback modules. Regeneration and strict checking find no stale event output or check errors.
  • The retained interpreter/Luau replays agree at 136 checkpoints, including the prologue through frame 59,566. Twenty-four checkpoints compile no Luau modules. These are bounded replay checks, not complete gameplay coverage. docs/PORT_LUAU.md provides the tracked input and checkout-relative commands for both VMs.

The bytecode files, interpreter bridges and timing normalization remain necessary: 125 scripts across all kinds still use the interpreter. The harness does not certify every native handler or execution path.

Rebase validation (2026-10-24)

Rebased the six-commit series onto current upstream master, f344ede3dbc5eac1e06d6a446c6acd036ae6ca73. The published head is e72132c9a403f86a0755acd884c2738b9c37d70b. Original authors, timestamps and messages are retained; committer identity was corrected for publication. The generated Luau corpus is unchanged from the original PR.

The integration retains the upstream monster stun/resume regression and both event tests. Event modules bypass the bytecode loader, so the runtime now applies upstream's exact per-script Spanish jump-gate text corrections for f04_5 and s30_5 before string interning. A regression test covers corrected, unrelated and custom text plus cache ordering.

Local validation of the published tree: 355 Python tests OK with one optional timing skip; all 7,995 Luau modules pass strict checking with zero diagnostics; generated API declarations, Luau pruning and diff checks pass. A focused compiled probe of the exact string-interning body with real Windows CP932 conversion passes 18 cases; its lookup and instance registry are fixtures, so it is not the full native runtime suite. Game-data differential corpus gates and gameplay replays were not rerun for this rebase. The earlier validation above applies to the original head as labelled.

Exact-head GitHub CI:

Check Result
discord skipped
report skipped
Build and test failure
Build the Flatpak (Linux x86_64) success
Build and test (Windows x64) failure
compiler success
Build and test (macOS arm64) failure

The three native build jobs fail while linking darkchronicle_tests (darkchronicle_tests.exe on Windows): CNameRegiMenu::CNameRegiMenu() is undefined, referenced by the NameEntryInput fixture in menu_input_test.cpp. The same symbol and fixture fail on all three platforms in the exact upstream-base run at f344ede3dbc5eac1e06d6a446c6acd036ae6ca73. The related name-entry implementation, headers, fixture and test target definition are unchanged by this PR. No PR-specific regression was identified in these failure logs.

The Luau runtime test source compiled, but the native test steps were skipped because the test executable could not link. In particular, the new Spanish text runtime regression has not executed in CI. Compiler integration and the Flatpak build/startup passed. Native runtime validation remains blocked by the verified upstream constructor-link issue; this rebase is not a green native-CI result.

An audit of the event handlers that read a slot's tag or write an
output, against ps2/src:

- tagged: GetRand, SetBgmVol, SndSetSeVol and EsmSetValue branch on an
  integer or float tag.
- strings: MesMake, MapJump, EsmLoadBase, StreamOpen, LoadSkin and the
  other commands that take a number or a name by the slot's tag.
- values: JoinPartyMember joins or leaves given a value and reports
  membership given a reference; GetMenuEtc's fish record and download
  step read a value where its other requests write.
- by_arg: GetMenuEtc writes a float for the fish record.
- deferred: GotoUseItem and GotoUseItem2 write the item used when their
  menu closes.
- kept: the argument scripts' Data keeps each argument's tag.

The outputs catalogued unknown get the type their handlers write.
LoadSkin reads four slots, so the curation can now remove a signature
the generator counted from two alternative reads. The declarations add
ExtTyped, which passes each argument with the tag retail pushed and
returns the outputs, and DeferredOutput, and the bindings mark deferred
outputs.
- Event scripts also run skipped at their first, second, third, fifth
  and ninth wait and at every wait.
- STATE models event story and local flags, quest fields and party
  membership; RANDOM draws event GetRand inside its range in the
  variant's type.
- Integer-or-string, kept and valued arguments compare as tag and
  payload; a value passed for an output is read, not written, and an
  output's type may follow the request (by_arg).
- A print records how retail formats each slot (%d, %f or the string),
  and the module's printed text must match it as well as the value.
- The mutation sweep reads ExtTyped calls and samples an event and an
  event argument script.
- A harness or mutation run copies only the libraries its module
  requires, which keeps the tool tests inside their timeout.
SkipEvent resumes an event script in skip mode: until the next SKIP_END
it runs in layout order, jumps fall through and leave their conditions
on the operand stack, native calls only pop their arguments, and
stores, prints and script calls run. stb/cfg.py's skip_flow finds each
function's sweeps, where they start and where normal execution resumes;
the analyses interpret them; the lifter lifts each into straight-line
statements; and the emitter puts them in a local skip(at), entered after
a wait the engine skipped, after a call that returned in skip mode and
at the start of a function a sweep calls. vm.wait returns whether the
engine skipped, and vm.skipping and vm.skip_end follow the mode.

The leaked conditions can overflow the 0x80-slot event stack where
normal execution does not. A function where that may happen takes its
frame's start, counts what its sweeps leave, and checks each push that
may overflow with vm.stack after evaluating, in bytecode order, the
calls and errors below it. What skip mode makes undefined, such as a
store through a leaked condition, is refused.

Also:
- A discarded value still evaluates what may raise or call: a store's
  value and element index nothing reads, a dropped result, a popped
  expression. A value passed for an output that may raise is refused.
- An expression of a store's result uses the value stored, as retail
  pushes it, rather than reading the element again.
- A tag analysis settles on the least tags the calls pass, records the
  tags of printed values, and a float slot prints with %f.
- A caller of a shared helper whose value another script uses takes the
  references after it.
- A deferred output is reinterpreted as its variable holds it, and an
  ExtTyped call passes the tags retail pushes.
938 of the 974 event and event argument scripts transpile; the other 36
stay on the interpreter, each with its reason in fallback.json. The
action, effect and monster modules change only where they print a
float slot.
The event and event_arg kinds join the generated bindings, so their
modules load where present. CRunScript::skip resumes a Luau script with
true, which puts it in skip mode. ExtTyped passes each argument with
the tag its letter names and returns the I and F outputs, and a
deferred output points at a slot that outlives the call, which
DeferredOutput reads after the following wait. The runtime tests cover
skip mode and the event natives, and CTest checks the event modules
against the corpus as Luau.TranspileEvent, a longer test of its own.
PORT_LUAU.md describes skip mode, the event handler flags, ExtTyped and
DeferredOutput, the stack checks, the harness's event state and print
text, and the Luau.TranspileEvent gate, which PC.md lists with the
other corpus tests. tools/input/luau-m4-prologue.input plays from boot
through the costume select and the prologue into Palm Brinks, with the
command that compares its screenshot and log on both VMs. The handoff
records the M4 results and what stays on the interpreter.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant