# Project Structure Layout for the *姫狩りダンジョンマイスター* (Himegari) → open AGE-engine reimplementation. The guiding rule is **source vs. derived vs. our work**: the shipped game is read-only input, the extracted archives and everything our tools generate are disposable/reproducible, and our code + docs live entirely apart from the game install. Nothing we produce is ever written back into the game folder. Workspace root: `S:\Game Hacking\Eushully\Himegari\` ``` S:\Game Hacking\Eushully\Himegari\ ← workspace root (three siblings) │ ├── 姫狩りダンジョンマイスター/ ← SOURCE — pristine game install (read-only) │ │ Never edit, move, or add to this folder. It holds ORIGINALS ONLY. │ ├── AGE.EXE, AGERC.DLL, *.dll shipped engine (packed). Stays intact and │ │ runnable in place — Frida launches it if needed. │ ├── DATA1-5.ALF, APPEND01.ALF/.AAI shipped archives (~2.3 GB). │ ├── *.BIN 52 loose patch-override scripts (v1.03) — │ │ AUTHORITATIVE over their DATA1 copies. Plus │ │ non-script indices (SYS4INI=S4IC, SYS4AB=S4AB). │ └── *.exe (uninstallers), SAS0099.OGG … other shipped files. │ ├── extracted/ ← DERIVED (game-side) — extracted ALF contents, │ │ ~3.9 GB, regenerable via age-reimpl/bin/BinExtractALF. │ └── DATA1/ … DATA5/ DATA1 = 481 .BIN scripts (the corpus we parse) │ + AGF/BMP/WAV in the others. │ └── age-reimpl/ ← OUR WORK (everything we made lives here) │ ├── tools/ Python tooling (parser/disassembler + extractors + VM) │ ├── paths.py ★ central path anchor — the ONLY place that knows │ │ where the game / extracted / build dirs are. All │ │ tools import it; relocatable with no other edits. │ ├── sys4load.py loader + disassembler (opcode-decoding) │ ├── age_opcodes.py 548-entry Kelebek AGE opcode/arg-type table (PRISTINE; never edit) │ ├── opcodes_build.py generator/linter: vm-map/opcodes.toml -> the 4 artifacts below │ ├── opcodes_model.py load + lint (dangling-ref, confidence-ceiling, vocab) + dependents │ ├── age_opcodes_himegari.py GENERATED from opcodes.toml (do not hand-edit) │ ├── vm0.py headless Python VM (Phase A0); `--test` = RECOVER unit test │ ├── extract_phase2.py batch: disasm + text + data extraction │ ├── extract_init.py, global_map.py … *INIT parsers, global-var map builder │ ├── validate_opcode_table*.py decode-coverage validators │ └── probe_*.py format reverse-engineering probes (historical) │ ├── bin/ 3rd-party binaries we use (not ours, not the game's) │ ├── BinExtractALF.exe ALF archive extractor → produces extracted/ │ └── LzssCpp.dll its LZSS codec dependency │ ├── vm-map/ VM / reverse-engineering reference artifacts │ ├── opcodes.toml ★ CANONICAL opcode reference (hand-edited: ABI + semantics │ │ + provenance + depends_on). Single source of truth for opcodes. │ ├── kelebek1-age-shared.cpp / -disassembler.cpp upstream opcode-table source │ └── opcode-leads.json, small-script-listings.md │ ├── docs/ all documentation │ ├── PROJECT-STRUCTURE.md this file │ ├── remake-architecture-and-roadmap.md THE direction doc (phases A–E) │ ├── phase-a-slice-plan.md the current slice (A0/A1/A2) │ ├── vm-mapping-plan.md the phased decode plan │ ├── himegari-port-reference.md master reference + engine background │ ├── name-resolution.md call-script + global-var name recovery │ ├── sys4-format-notes.md byte-level container format │ ├── script-inventory.md what the 481 scripts are │ └── opcode-reference.md GENERATED from opcodes.toml (human-readable opcode reference) │ ├── build/ DERIVED (our-work-side) — generated by tools/; disposable │ ├── disasm/ .asm — human-readable disassembly, one per script │ ├── text/ extracted text: │ │ ├── .strings.txt all inline strings in a script │ │ ├── dialogue.jsonl show-text lines only (the translation corpus) │ │ └── strings.jsonl every string, tagged by source opcode │ ├── data/ parsed data tables (*INIT → JSON) │ ├── scripts-json/ machine-readable full dumps (on demand via --json) │ ├── global-var-map.{json,md} partial global-variable name map │ ├── opcodes.json GENERATED from opcodes.toml (machine view for the C# VM) │ └── manifest.json, opcode-coverage.md (opcode-coverage.md GENERATED from opcodes.toml) │ └── godot/ DELIVERABLE — the Godot/C# engine project (built in Phase A2+) ``` ## Conventions - **Three-way separation.** `姫狩りダンジョンマイスター/` = untouched originals; `extracted/` = game-derived data (regenerable, game-side); `age-reimpl/` = everything we authored. The first two are consumed, never modified. - **Tools never hard-code paths.** `tools/paths.py` derives `GAME_DIR`, `EXTRACTED`, `DATA1`, `BUILD`, etc. from its own location. To point the tools at a different install, edit that one file. The whole tree can be relocated without touching any other tool. - **Path references in docs** are `age-reimpl/`-relative (e.g. `tools/sys4load.py`, `build/text/dialogue.jsonl`) unless they name a game/extracted path explicitly. - **Authoritative script copies:** where a script exists both as a loose `.BIN` in the game folder and under `extracted/DATA1/`, the game-folder copy (patch v1.03) wins. `paths.scripts()` resolves this automatically (overrides win). - **`build/` and `extracted/` are disposable.** `build/` regenerates via `tools/extract_phase2.py` (or `sys4load.py`); `extracted/` regenerates via `bin/BinExtractALF.exe` on the `.ALF` files. Safe to delete and rebuild; do not hand-edit. - **Opcode knowledge is edited ONLY in `vm-map/opcodes.toml`** (ABI + semantics + provenance + `depends_on`). Run `tools/opcodes_build.py --build` to regenerate the shim (`tools/age_opcodes_himegari.py`), machine JSON (`build/opcodes.json`), reference (`docs/opcode-reference.md`), and coverage. `--lint` checks dangling deps / confidence-ceiling / vocabulary. Kelebek's `tools/age_opcodes.py` stays pristine. - **Encoding:** all generated text is UTF-8 (source strings are cp932/Shift-JIS, decoded on extraction). Run Python as `py -3.11 -X utf8`. - **The game install is a runnable unit** — do not relocate `AGE.EXE`/`*.ALF`/DLLs relative to each other, or the game (and any Frida work) breaks.