GridFight extractor (Node ESM)
Faithful port of the sibling extractor. Node 22+ and built-in modules only;
validated with Node 26.12.0. Native reader proofs require GNU objdump.
Linux installers use flock. XXH64 is implemented locally: no FFI, libxxhash,
npm install, metadata dumper, network fetch or game launch is required.
Run from the repository root:
node tools/gridfight-extract-node/extract.mjs \
--client /path/to/client \
--dump /path/to/config/dump.cs \
--output /tmp/gridfight-core \
--traits --season-id 2 \
--evidence-dir /tmp/gridfight-core/evidence
node --test tools/gridfight-extract-node
The dump must contain RPG.GameCore.Config.dll; traits also need
RPG.GameCore.Foundation.dll and RPG.GameCore.FixedMath.dll. Use the matching
config/dump.cs, rather than assuming the top-level dump contains those rows.
Treat client files as read-only; place outputs and evidence outside the client.
extract.mjs retains --language (default en, choices en cn cht jp kr de es fr id pt ru th vi), --traits, --season-id, and --evidence-dir. It publishes
roles, shop odds, traits/layers, season/divisions, offerings, schemas and
provenance with the same filenames and JSON contracts as the reference.
Season selection is explicit; it does not establish a live calendar.
Native mask tests and metadata establish field order. Every native indexed collection must decode completely and re-encode to its exact original bytes. Unknown types, absent/ambiguous assets, conflicting text and invalid references fail. Required data documents publish only after the requested validations succeed. Evidence may remain after failure. Each replacement is atomic; use a staging directory for bundle-level installation. Large integers retain all 64 bits in JSON. Arrays, numeric dictionary ordering, indentation and Unicode escaping retain the reference output representation.
Other entrypoints preserve their original flags (.mjs replaces .py):
| Entrypoint | Required flags | Optional flags/defaults |
|---|---|---|
stages.mjs |
--client --dump --identity --output |
None |
items.mjs |
--client --dump --identity --output |
None |
petpal.mjs |
--client --dump --identity --output |
None |
rounds.mjs |
--client --dump --literals --identity --output |
--language en |
trait_effects.mjs |
--client |
--output resources/grid_fight/trait_effects.json |
trailblaze.mjs |
--client |
--output resources/grid_fight/trailblaze.json |
jade.mjs |
--client |
--output resources/grid_fight/jade.json |
equipment.mjs |
None | --items, --catalog, --season 2, --output |
portals.mjs |
None | --items, --catalog, --season 2, --output, --augments |
score.mjs |
None | --catalog, --output |
ui_names.mjs |
--client --dump --resources --english --thai --output --evidence |
None |
native_slice.mjs |
--client --dump --class --output |
Repeat --class |
audit_coverage.mjs |
--dump --output |
--source defaults to repository root |
audit_battle_entry.mjs |
--client --dump --assembly --roles --evidence |
None |
install_stages.mjs |
--source --launcher --stage --report |
--package stage or petpal |
install_rounds.mjs |
--server-root --launcher-root --stage |
None |
run_tests.mjs |
--output |
--zig zig (requires 0.14.1 and cached protobuf) |
Default derived-table inputs and outputs remain repository-relative:
resources/grid_fight/items.raw.json, the matching basename's JSON, and
protocol/evidence/cw-mechanics/catalog.json. Portals also writes
resources/grid_fight/augments.json. Pass scratch output paths for comparison.
For example:
node tools/gridfight-extract-node/items.mjs \
--client /path/to/client --dump /path/to/config/dump.cs \
--identity /tmp/gridfight-core/provenance.json --output /tmp/gridfight-items
node tools/gridfight-extract-node/equipment.mjs \
--items /tmp/gridfight-items/items.raw.json --season 2 \
--catalog /path/to/matching/catalog.json --output /tmp/gridfight-equipment.json
stages, items and petpal consume the core extractor's identity manifest.
rounds consumes the client-table metadata identity (client and
metadata_sha256) and matching string literals. Its underscore raw filenames,
Supply null, and tagged DynamicValue contract intentionally differ from
stages (dot raw filenames, Supply shop, and wire_tag). Neither guesses
monster groups or tutorial selector meanings.
Installers retain identity/hash checks, a nonblocking runtime-refresh lock,
verified backups, atomic replacements, manifest refresh, protected-file checks
and rollback. They use a local Node port of the runtime verification helpers.
install_rounds stores its audit evidence in this new directory, preserving
the sibling reference directory. No installer was run against real resources;
installation was exercised only in disposable fixtures.
Full season-2 staging, including a fresh native catalog for equipment/score and a file-by-file installed-data comparison:
node tools/gridfight-extract-node/stage_all.mjs \
--client /path/to/client --dump /path/to/config/dump.cs \
--literals /path/to/stringliterals.json \
--english /path/to/active/en/TextMap.bytes \
--thai /path/to/active/th/TextMap.bytes \
--resources /path/to/server/resources \
--baseline /path/to/server/resources/grid_fight \
--output /tmp/cw-stage
The output must be outside the client and installed resources. All flags are required; no derived entrypoint falls back to the older repository catalog in this workflow. The active language blobs must match the client. Logs, native proofs, CHANGES.md, comparison.json and a hashed bundle manifest accompany the runtime JSON. Root rounds use the existing stages contract; the alternate rounds extractor's distinct contract is retained under rounds-alternative/. Server-authored node_profiles/orb_rewards are carried byte-identically, marked as third-party observations rather than freshly extracted client data. Old backup files are compared in the report but excluded from the runtime bundle. AvatarConfig/AeonCatalog provide existing UI identity/name lookup hints; UI text is resolved from the supplied client TextMaps. Staging does not install data.
Validation on OSBETAWin4.6.53, season 2:
- 51 tests pass, including native 4.6.53 dispatch mutation rejection, relocated 4.6.51 layout, nested nulls, signed 64-bit limits, NaN payloads, dictionary doubles and the Phainon schema's stack-write regression.
- DynamicValue FromByteBinary resolves from metadata (4.6.53 RVA 0x1e745df0; 4.6.51 RVA 0x1e58e120). Both use case offsets 0x85/0xc5/0x102/0x14f/0x18a/0x1cf and dispatch offset 0x2b0. Typed case operations and dispatch bindings must match before evidence is published. The wire layout is unchanged; both projection modes support null tag 6. Integer and float bytes stay lossless.
- Stages: all 14 tables, including 29,715 StageConfig rows, re-encode exactly. Fresh supplemental catalog: all 20 additional tables re-encode exactly, including all nine Phainon fields (stack addresses are excluded from native field candidates). Both stage and alternate-rounds extraction complete.
- 141 roles, 11 shop levels, 67 traits, 304 season-2 augments, 74 season-2 portals, 147 season-2 equipment entries, 493 routes, 12 partners. Trial-avatar audit: 5,200 rows re-encoded exactly and all 141 role identities verified.
- ui_names also exports item/augment/portal/trait hash maps for ID comparisons; the current run resolves 1,816 English and Thai texts.
- No client data, installed resources, reference Python code, archives or live processes are changed. No gameplay-correctness claim is made.
Use node --test tools/gridfight-extract-node. On hosts whose default test
isolation reports only a file-level result, add --test-isolation=none to see
all 51 individual results. Native proof fixtures are static objdump excerpts
from the matching beta DLL; method offsets come from config/dump.cs.