feat(startup): add configurable game root
This commit is contained in:
@@ -11,7 +11,7 @@ Workspace root: `S:\Game Hacking\Eushully\Himegari\`
|
||||
```
|
||||
S:\Game Hacking\Eushully\Himegari\ ← workspace root (three siblings)
|
||||
│
|
||||
├── 姫狩りダンジョンマイスター/ ← SOURCE — pristine game install (read-only)
|
||||
├── Himegari_Game/ ← 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.
|
||||
@@ -101,8 +101,9 @@ S:\Game Hacking\Eushully\Himegari\ ← workspace root (three siblings)
|
||||
│ └── manifest.json, opcode-coverage.md (opcode-coverage.md GENERATED from opcodes.toml)
|
||||
│
|
||||
├── engine/ DELIVERABLE — the .NET VM core (AgeEngine.sln: Age.Engine / Age.Cli / tests)
|
||||
│ ├── Age.Engine/Sys4/ runtime catalog parser, loose-first bounded ALF asset store,
|
||||
│ script provider, AGF/LZSS and Windows CUR decoders, and resource facade
|
||||
│ ├── Age.Engine/Sys4/ runtime game-root selection, catalog parser, loose-first bounded
|
||||
│ ALF asset store, script provider, AGF/LZSS and Windows CUR decoders,
|
||||
│ and resource facade
|
||||
│ └── Age.Engine/Persistence/ native S3SD/S4SD + S3RT codecs, shared payload/ReadTextDB,
|
||||
│ layout-3 numbered state/history/gfx, DAT/STH pair + BMP codec,
|
||||
│ and profile-owned state
|
||||
@@ -119,7 +120,7 @@ page ordinals to their authoritative script offsets for `tools/locate_page.py`.
|
||||
|
||||
## Conventions
|
||||
|
||||
- **Three-way separation.** `姫狩りダンジョンマイスター/` = untouched originals; `extracted/` =
|
||||
- **Three-way separation.** `Himegari_Game/` = 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`,
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
Working reference for porting *姫狩りダンジョンマイスター* (Eushully, 2009) to Godot.
|
||||
|
||||
Source install: `C:\Program Files (x86)\Eushully\姫狩りダンジョンマイスター\`
|
||||
Workspace: `S:\Game Hacking\Eushully\Himegari\` — three siblings: `姫狩りダンジョンマイスター\` (pristine game), `extracted\` (extracted ALF data), `age-reimpl\` (our work). See `docs/PROJECT-STRUCTURE.md`.
|
||||
Source install: `S:\Game Hacking\Eushully\Himegari\Himegari_Game\`
|
||||
Workspace: `S:\Game Hacking\Eushully\Himegari\` — three siblings: `Himegari_Game\` (pristine game), `extracted\` (extracted ALF data), `age-reimpl\` (our work). See `docs/PROJECT-STRUCTURE.md`.
|
||||
|
||||
---
|
||||
|
||||
@@ -91,10 +91,10 @@ loop in `AGE.EXE`, which is the Ghidra task below. Graphics conversion (DATA2/5
|
||||
save-format work remain deferred.
|
||||
|
||||
### Immediate (no tools needed beyond what's on disk)
|
||||
1. ~~**Relocate the `Output\` tree**~~ **DONE** — workspace now at `S:\Game Hacking\Eushully\Himegari\姫狩りダンジョンマイスター\`.
|
||||
1. ~~**Relocate the `Output\` tree**~~ **DONE** — pristine install now at `S:\Game Hacking\Eushully\Himegari\Himegari_Game\`.
|
||||
2. **Convert remaining AGFs** in DATA2 (985 files) and DATA5 (210 files) with `AGF2BMP2AGF.exe`. *(Deferred — graphics not needed yet.)* The 3-file DATA1 gap is `CHAPTER.AGF`, `LOGO.AGF`, `TEST.AGF`.
|
||||
3. ~~**Inventory the script files**~~ **DONE** — see [script-inventory.md](script-inventory.md). Key findings: all 481 scripts share magic `SYS4422 `; 49 loose root-dir script `.BIN` files shadow DATA1 copies (plus two root-only engine BINs; use overrides as authoritative); heavy game logic (damage calc, dungeon loop, battle flow) lives in bytecode, favoring a VM re-implementation in Godot.
|
||||
1. ~~**Relocate the `Output\` tree**~~ **DONE** — workspace now at `S:\Game Hacking\Eushully\Himegari\姫狩りダンジョンマイスター\`.
|
||||
1. ~~**Relocate the `Output\` tree**~~ **DONE** — pristine install now at `S:\Game Hacking\Eushully\Himegari\Himegari_Game\`.
|
||||
2. **Convert remaining AGFs** in DATA2 (985 files) and DATA5 (210 files) with `AGF2BMP2AGF.exe`. *(Deferred — graphics not needed yet.)* The 3-file DATA1 gap is `CHAPTER.AGF`, `LOGO.AGF`, `TEST.AGF`.
|
||||
3. ~~**Inventory the script files**~~ **DONE** — see [script-inventory.md](script-inventory.md). Key findings: all 481 scripts share magic `SYS4422 `; 49 loose root-dir script `.BIN` files shadow DATA1 copies (plus two root-only engine BINs; use overrides as authoritative); heavy game logic (damage calc, dungeon loop, battle flow) lives in bytecode, favoring a VM re-implementation in Godot.
|
||||
|
||||
|
||||
@@ -3569,6 +3569,33 @@ and an overridden `1200x700` request while continuing to report `logical-canvas=
|
||||
width exits during startup with the expected diagnostic. Headless's minimized `64x64` backend remains
|
||||
non-authoritative for visible client geometry.
|
||||
|
||||
### Runtime game-root selection result (implemented 2026-07-28)
|
||||
|
||||
Godot no longer obtains installed game data from the development-only `Paths.GameDir` workspace
|
||||
assumption. `GameRootSelection` establishes one normalized read-only root before loading SYS4INI:
|
||||
`--game-root <directory>` has highest precedence, followed by the running executable's directory and
|
||||
then the current working directory. Candidates are accepted only when `SYS4INI.BIN` is present.
|
||||
Relative overrides resolve against the working directory, repeated options use the last value, and an
|
||||
invalid explicit override fails without silently selecting a different install. On Unix the frontend
|
||||
uses inherited shell `PWD` as the launch working directory because Godot can change the process directory
|
||||
to its project before managed startup.
|
||||
|
||||
The selected root supplies the base catalog, loose overrides, append catalogs, and ALF archives through
|
||||
one injected `Sys4AssetStore`. Normal execution, the debug-scene catalog, and threaded self-test reuse
|
||||
that same catalog/store rather than re-entering repository path discovery. The local ignored
|
||||
`run-godot.ps1` development convenience passes one directly configured `$gameRoot` value because editor
|
||||
runs are hosted by the Godot executable; changing that assignment is the local cross-game testing seam.
|
||||
An exported executable placed beside the original game data can use the executable-directory default.
|
||||
This is the command-line boundary a future multi-profile launcher can populate with an absolute install
|
||||
path.
|
||||
|
||||
Eight focused cases cover explicit and relative selection, override precedence and duplicates,
|
||||
executable-directory defaulting, working-directory fallback, missing values, invalid explicit roots,
|
||||
and unresolved diagnostics. The complete engine suite passes **463/463**, the Godot project builds with
|
||||
zero warnings, and the threaded headless self-test reports the selected `launch-argument` game root
|
||||
before `SELFTEST OK`. Export packaging of generated opcode/profile metadata remains a separate
|
||||
distribution step; this slice removes the installed-game hardcoding only.
|
||||
|
||||
## ADV requested-face selection implemented (2026-07-28)
|
||||
|
||||
Opcode `0x1a5` is no longer a presentation no-op. The VM retains its requested face in
|
||||
|
||||
@@ -35,7 +35,7 @@ or replaced before claiming portable exports.
|
||||
| ADV font discovery/raster fidelity | Opcode `0x1a5` reaches presentation; `godot/Main.cs` loads Windows `MS 明朝`/`MS ゴシック` from their known TTC files when available, otherwise uses the existing Japanese-font/default fallback. AGE actually uses a display information DC, weight-700 `LOGFONTA`, `GGO_GRAY4_BITMAP`, and its own integer glyph/outline compositor; the current `Label` backend substitutes FreeType embolden and a Godot outline | On the reference Windows install, regular advances and direct SC0000 placement/bounds agree, but the behaviorally different provisional bold path has 45% fewer bright pixels and much softer edge coverage. Other platforms normally lack the proprietary faces, so substitute metrics remain profile-dependent | Deferred until gameplay settles: implement the Phase-E decoded mask/metrics/compositor backlog in `docs/remake-architecture-and-roadmap.md`, with a shipped GDI reference backend on Windows and an explicitly defined portable rasterizer/substitution policy |
|
||||
| Filesystem semantics | Several filename and containment comparisons use `OrdinalIgnoreCase`; installed assets are conventionally uppercase | Needs validation on case-sensitive filesystems; may hide casing or containment mistakes | Add Linux/macOS tests with mixed-case synthetic roots and use filesystem-appropriate containment rules |
|
||||
| Save/profile storage | Managed `DirectoryNativeDatStore` under Godot `user://SAVE`; native S3SD/S4SD/S3RT files and 24-bit BMP thumbnails | No Win32 path API at runtime; port saves remain isolated from the original installation | Validate replace/flush, case, permissions, and interrupted-write behavior on each export target |
|
||||
| Install/repository discovery | `engine/Age.Engine/Sys4/Paths.cs` finds `age-reimpl` above `AppContext.BaseDirectory` and assumes the current workspace sibling layout | Suitable for development, not packaged exports on any OS | Replace runtime discovery with a user-selected game root/profile; retain repository paths only for developer tools/tests |
|
||||
| Game-install and repository discovery | `GameRootSelection` accepts `--game-root`, then probes the executable directory and current working directory for `SYS4INI.BIN`; on Unix the frontend prefers inherited shell `PWD` because Godot may change the process directory during project startup. Godot injects the selected root into its catalog and loose-first ALF store. `Paths.cs` remains the development/test locator for generated opcode data, diagnostics, and CLI conveniences | Installed game data no longer depends on the workspace sibling layout, enabling an executable beside `AGE.EXE`, a terminal launch from the install, or a launcher-supplied absolute profile root. A packaged export still needs its generated runtime metadata bundled independently of repository discovery | Add export packaging for the opcode/profile artifacts, let the future profile launcher pass `--game-root`, and run executable-directory/CWD plus case/permission smoke gates on Linux and macOS |
|
||||
| Archive parity oracle | One integration test launches `bin/BinExtractALF.exe` | Windows-only test helper, not a shipped runtime dependency | Skip/replace on non-Windows CI; runtime ALF/AAI readers do not depend on it |
|
||||
| Native RE tools | Frida/Ghidra helpers target the original `AGE.EXE`; supporting utilities include Windows executables and Windows command conventions | Development/research only | Keep separate from export requirements; document platform prerequisites per tool |
|
||||
| Python workflow | Operating guide uses Windows `py -3.11` invocation | Developer workflow only | Add equivalent `python3` instructions if non-Windows development becomes active |
|
||||
|
||||
@@ -649,6 +649,14 @@ the toolchain at the new game's archives, re-run extraction, rebuild its global
|
||||
**This is the core payoff of the VM approach:** the *engine* cost amortizes across all AGE games; only
|
||||
content-mapping recurs — far less than re-coding each game's logic bespoke.
|
||||
|
||||
The first runtime install-selection boundary is now in place. Godot receives one normalized game root,
|
||||
defaulting to the executable directory with a current-working-directory fallback and accepting an
|
||||
explicit `--game-root` override; the selected root is injected into the generic SYS4 catalog/store
|
||||
instead of inferred from the Himegari repository layout. A future multi-profile launcher can therefore
|
||||
own install discovery and pass the chosen profile's absolute root through the same stable argument.
|
||||
Generated engine/profile metadata still needs an export-owned bundle before this constitutes complete
|
||||
drop-in packaging; invocation details live in `tools-reference.md`.
|
||||
|
||||
#### Opcode ABI registry must be independent of per-game coverage
|
||||
|
||||
A cursory Kamidori boot probe on 2026-07-20 validated much of this boundary: its own `SYS4INI.BIN` and
|
||||
|
||||
@@ -162,7 +162,7 @@ public static class Paths
|
||||
public static string Workspace => Directory.GetParent(Repo)!.FullName;
|
||||
public static string Extracted => Path.Combine(Workspace, "extracted");
|
||||
public static string Data1 => Path.Combine(Extracted, "DATA1");
|
||||
public static string GameDir => Path.Combine(Workspace, "姫狩りダンジョンマイスター");
|
||||
public static string GameDir => Path.Combine(Workspace, "Himegari_Game");
|
||||
public static string Build => Path.Combine(Repo, "build");
|
||||
public static string OpcodesJson => Path.Combine(Build, "opcodes.json");
|
||||
|
||||
|
||||
@@ -298,11 +298,24 @@ at 2.5M lines). All observe-only → parity preserved; all on `run`/`play`/`swee
|
||||
|
||||
**Godot frontend** (`S:/Godot/Godot_v4.7…`; project = `godot/`). Toolchain: `godot --headless --path godot
|
||||
--import` → `dotnet build godot/Himegari.csproj` → `godot [--headless] --path godot [-- <userargs>]`.
|
||||
Plays the real bytecode with call-script execution on (subroutines run live). A no-argument launch starts
|
||||
the persistent `SYSTEM4.BIN` root and reaches TITLE naturally. The local `run-godot.ps1`/`.cmd` launchers
|
||||
make that route explicit with `--scene SYSTEM4` and pass neither `--boot` nor SC0000 seeds. `--headless` can't
|
||||
render texture ops (no GPU context) — run windowed for real scenes. On VM termination the console prints
|
||||
the exact halt reason and step count before the generic on-screen `-end-` marker. User args (after `--`):
|
||||
Plays the real bytecode with call-script execution on (subroutines run live). The game root is selected
|
||||
before catalog loading: `--game-root <directory>` wins, otherwise the directory containing the running
|
||||
executable is tried, then the current working directory. A candidate must contain `SYS4INI.BIN`; invalid
|
||||
explicit roots and unresolved defaults stop startup with the searched locations. Relative overrides are
|
||||
resolved against the current working directory, and repeated overrides use the last value. On Unix,
|
||||
Godot preserves the shell launch directory through inherited `PWD` because editor/project startup may
|
||||
change the process directory before managed code runs.
|
||||
|
||||
With the exported executable placed in an AGE install, a no-argument launch therefore uses that install
|
||||
and starts the persistent `SYSTEM4.BIN` root naturally. Direct development runs are hosted by the Godot
|
||||
editor executable, so pass `--game-root <install>` after Godot's `--` separator; the local
|
||||
`run-godot.ps1`/`.cmd` launchers pass the local script's directly configured `$gameRoot` value. Edit that
|
||||
one assignment when testing another installed game. Those launchers make the natural route explicit with
|
||||
`--scene SYSTEM4` and pass neither `--boot` nor SC0000 seeds. Examples below focus on their
|
||||
feature-specific arguments and assume the game root is already selected this way. `--headless` can't
|
||||
render texture ops (no GPU context) — run windowed for real scenes.
|
||||
On VM termination the console prints the exact halt reason and step count before the generic on-screen
|
||||
`-end-` marker. User args (after `--`):
|
||||
|
||||
The local launchers also accept **`-StartupDiagnostics`** for a native-faithful cold boot through TITLE,
|
||||
Game Start, and SC0000. The switch overrides `run-godot.cmd`'s usual `-NativeDebugMenu` convenience for
|
||||
@@ -316,6 +329,9 @@ wait, optionally press F3, and close the window normally. Until shutdown cancell
|
||||
ADV input release, normal window close can append one trailing shutdown-only record to `page-map.jsonl`;
|
||||
use the last `input-wait` event in `timeline.jsonl` as the authoritative manual stop coordinate.
|
||||
|
||||
- `--game-root <directory>` — select the read-only AGE installation supplying `SYS4INI.BIN`, loose
|
||||
overrides, AAI append catalogs, and ALF archives. Absolute paths are launcher-friendly; relative paths
|
||||
are current-working-directory-relative. This is the stable handoff for future game-profile launchers.
|
||||
- `--scene <NAME>` — override the default `SYSTEM4` root with a direct diagnostic scene, e.g. `--scene SC0240` (executes 29 nested subroutines).
|
||||
- `--selftest` — headless; runs a **synthesized** scene through the thread/suspend/`CallDeferred` plumbing and asserts it matches a live headless run (full handling; no vm0/frozen golden). Exits.
|
||||
- `--window-width <pixels>` / `--window-height <pixels>` — override only the physical windowed client
|
||||
|
||||
Reference in New Issue
Block a user