Files
OpenMaidEngine/docs/PROJECT-STRUCTURE.md
gamer147 a61c0c9abd feat(assets): solve asset resolution (SYS4INI per-scene section manifest)
resId -> files[section_base(scene) + resId]. SYS4INI's file list is
sectioned, one per scene (SCxxxx.BIN + its cross-archive asset manifest);
file_number is the index within the section. Unified for set-texture,
play-bgm, play-voice. Fully static/general -> no per-scene capture.

- tools/parse_sys4ini.py: SYS4INI (S4IC422, LZSS) -> build/asset-index.json
- tools/resolve_asset.py: sections + (scene,resId) resolver -> build/asset-sections.json
- validated: 97% structural, SC0000 17/17 vs Frida, 586/595 captured loads
- opcodes.toml: set-texture/create/draw-texture, play-bgm/voice enriched (frida-grounded)
- Frida tooling (capture_load_order all-archive, correlate_scope, ...) + vm0 --settex
- docs: asset-resolution-re (step2 SOLVED), global-memory-re (shelved), tools-reference

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 20:48:22 -04:00

8.3 KiB
Raw Blame History

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 (where things live)
    │   ├── tools-reference.md                  every tool: purpose, usage, I/O (operational companion)
    │   ├── asset-resolution-re.md              resId→file RE (graphics/audio); asset-index steering
    │   ├── global-memory-re.md                 runtime global observation RE (SHELVED; future starting point)
    │   ├── remake-architecture-and-roadmap.md  THE direction doc (phases AE)
    │   ├── 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/                            <NAME>.asm — human-readable disassembly, one per script
    │   ├── text/                              extracted text:
    │   │   ├── <NAME>.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.