Files
goldeneye-pc-port/AGENTS.md
T
James Dansereau 48aba25c62 D88: verify D88.1-3 via -level_09; document D88.4 blocker + D75 render bugs
- prop.c/stan.c: GE_D88 env-gated diagnostic probes (proplvreset2 pad
  walk, stanMatchTileName tile walk). Zero cost when unset.
- Verified: proplvreset2 now walks the full pads table correctly
  (real plink strings, sane BUNKER1 coords); prop.c:1306 crash gone.
- D88.4 (new blocker): propDefs stream left un-byteswapped by the
  converter -> setupDoor/modelLoad crash on garbage door->obj.
- D75: expanded with confirmed symptoms (Nintendo logo mispositioned,
  gun-barrel Bond model missing, cast-roll character models absent).
2026-08-28 08:30:56 -04:00

54 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AGENTS.md — GoldenEye 007 PC Port
## What this is
- `n64decomp/007`: WIP decompilation of GoldenEye 007 (N64), byte-matches US/EU/JP ROMs.
- Active work: **PC port** modelled on the Perfect Dark PC port (same Rare "Indy" engine family).
- **Read `docs/PCPortResearch.md` first** — architecture, GE-specific RSP deltas, phased plan, and review findings (A1–D33 in §11; current handoff + plan in §H).
- **Starting a fresh session?** Read `docs/HANDOFF.md` — the paste-ready brief with the immediate task, standing procedure, and environment gotchas.
## Non-negotiables
1. **N64 build untouched.** `Makefile`, `tools/`, `rsp/`, `ld/` belong to the N64 build. Never modify them for the PC port.
2. **Game logic is unmodified.** The decomp's control flow and behavior are ground truth for 1:1 fidelity — never change them. All N64 *hardware* dependencies are satisfied by the `port/` layer; if a game file seems to need a behavioral change, stop — the fix belongs in `port/`. **Narrow exception (ABI/layout only):** the 32→64-bit transition forces a small class of mechanical, semantics-preserving edits that cannot be isolated in `port/` — chiefly pointer-width reconciliation in ROM-serialized structs (a struct with a 32-bit-pointer field misaligns when read as 64-bit). These follow the PD ground-truth pattern (store the embedded address as `u32`, cast to a real pointer at the use site), change no logic or behavior, and are each documented in `docs/PCPortResearch.md` §F/D3x. No other game-code edits are permitted.
3. **Region macros mirror the Makefile.** `CMakeLists.txt` `REGION_DEFS` must match the N64 Makefile's per-region macro set exactly (finding A1). Divergence = silent branch divergence + link failures.
4. **`src/libultrare/Makefile.libultrare` is ground truth** for original-vs-Rare libultra files (finding B3). The PC build compiles: `libultra/audio`, `libultrare/audio` (drvrNew/env/reverb), `libultra/gu`, and `libultrare/io/vitbl.c` only. All other `io/` + `os/` files are excluded and shimmed in `port/src/libultra.c`.
5. **`rsp/graphics/gmain.s` is the RSP ground truth** — the authoritative reference for which GBI commands GE emits (modified fast3d, 1545 lines). We do not run it on PC; `port/fast3d/` replaces it. Use it to validate the software RSP's command decoding and the custom CC/RM modes.
## Critical files
| File | Role |
|---|---|
| `docs/PCPortResearch.md` | Research + plan + findings (A1–C2). Read first. |
| `CMakeLists.txt` | PC build (parallel to the N64 Makefile). Source list + `REGION_DEFS` live here. |
| `port/src/` | Shims: `libultra.c` (OS API), `gesched.c` (scheduler), `n64stubs.c` (boot/TLB/FPU/rmon), `random.c` (PRNG ported verbatim from `random.s`), `ucode.c` (microcode segment markers), `main.c`, `video.c`, … |
| `port/fast3d/` | Software RSP (adapted from the PD port). The main Phase 2 work. |
| `rsp/graphics/gmain.s` | GE's RSP ucode — ground truth for GBI/CC/RM. |
| `PD_PORT_CHECKOUT` | Perfect Dark PC port checkout — **standing reference for this project**: consult it whenever a remaining work item has a PD analogue (same Rare engine family). Port-layer ground truth (`port/fast3d/`, crash/system/video), plus copy candidates: `port/src/preprocess/` (N64→PC asset conversion at load; `filemodel.c` is the D43 near-analogue, same vma 0x5000000) and `mixer.c`/`input.c`/`fs.c` (Phase 3/4 — our stubs were scaffolded to be replaced by these). Caveats: port-layer files only; same family ≠ identical format — validate per field. Full audit: `docs/PCPortResearch.md` §2.4. |
## Build
```sh
./build-pc.sh ntsc-final # or pal-final / jpn-final
```
Needs CMake + SDL2 + zlib + OpenGL (MSYS2 packages: see `build-pc.sh` header). ROM goes in `./data/` (not distributed).
## Verification ritual (after any build-affecting change)
1. **Undefined symbols.** Every symbol referenced by the compiled set (see `CMakeLists.txt`: `SRC_GAME`, `SRC_ENGINE`, `SRC_LIBAUDIO`, `SRC_LIBULTRARE_AUDIO`, `SRC_LIBULTRARE_DATA`, `SRC_GU`, `SRC_PORT*`) must be defined exactly once in the compiled set or in `port/`. Symbols that live in EXCLUDED files (`libultra/io/*`, `libultrare/io/*` except `vitbl.c`, `libultra/os/*`, `libultrare/os/*`, `sched.c`, `rmon.c`, `vi.c`, `src/*.s`) must be provided by `port/src/libultra.c`, `gesched.c`, `n64stubs.c`, `random.c`, or `ucode.c`.
2. **Duplicates.** No symbol defined twice across the compiled set (watch `sp_*` stacks, `rmon*`, `os*` shims, segment markers).
3. **Syntax.** Every touched file must parse; once the toolchain is installed, `./build-pc.sh` is the final word.
Run `/linkcheck` for this sweep. Record new findings in `docs/PCPortResearch.md` §11 style (next label after the last used).
## Phase status
- **Phase 0 (scaffolding):** done, committed.
- **Compile+link milestone:** all ~235 TUs compile and `ge007.x86_64.exe` links clean (`ninja ge007 -k 0`, 236/236). Findings D7–D17 in `docs/PCPortResearch.md` §11; asset stubs in `port/src/assetstubs.c`, fast3d no-ops in `port/src/gfxstub.c` (delete when real fast3d lands).
- **Phase 1 (boot to window):** done — ROM loads/validates/maps at cart base 0x10000000 (`romdata.c`), SDL2 window + GL clear loop (`video.c`), absolute asset symbols from `scripts/gen_romassets.py` → `port/src/romassets_<r>.s` (findings D18–D23).
- **Phase 1.5 (boot to first frame):** DONE — boot chain complete AND real frames render (`[NOTE] frame N rendered in … us`). D34–D42 closed the blockers on top of D31–D33: ANIM_DATA lvalues, music seq-table ABI+endianness, music-heap sizing, libaudio bank-tree re-layout, implicit-declaration prototype shim (D38), Globalimagetable rebasing + true segment size (D39), ModelHitEntry pool sizing (D40), cross-thread GL context release (D41), rsp task-settings toggle (D42). ROM dump verified against the No-Intro good dump (byte-identical, header CRCs re-checked — `tools_pc/romverify.c`).
- **Phase 2 (rendering):** IN PROGRESS — fast3d integrated + real frames render. **Plan B EXECUTED (D50, committed):** all 512 NTSC model files converted offline by `tools_pc/d43_emit.py` → `data/pcmodels-ntsc-final/pcmodels.bin` + manifest.csv (single concatenated RZ image; regenerate per region with the script — sidecars are gitignored), served through the existing load path via a port-layer table patch (`port/src/pcmodels.c`, romdata cart-extension, one-shot `pcmodelsPatchTable()` + poolRemaining reset hook in `load_object_fill_header`); runtime C fixups for language-bank BE offset tables + font re-layout (D50.3/D50.4); legal-screen UB seed (D50.5); **D50.6 fixed the first model-render crash** — `texCopyGdls` copied only w0 of each 16-byte Gfx slot on PC (the union's trailing `long long` is 8 bytes), leaving stale mempool w1s in the compacted GDLs; byte-proven against PlegalpageZ, fixed with a full-slot copy under #ifdef PORT. Model GDLs now execute to completion (PlegalpageZ sub-DLs). **D51 RESOLVED** (font `pixeldata` fixup wrote the pointer at the wrong offsets — frame-5 `import_texture_i8` crash gone; GE opcode space decoded along the way, G_TEXRECT=0xE4/0xE5 non-F3DEX numbering), **D52 RESOLVED** (`osGetCount` now advances at the N64 RSP counter rate ≈ 46.5525 ticks/µs — fixed the non-deterministic post-frame-2 hang), **D53 RESOLVED** (model RW-data pool addressing: D53.1 `Model.datas` word-stride → `u32 *` under PORT + casts; D53.2 ModelSlot/AnimModelSlot re-laid on top of the PC struct Model — in-use@0x10 / pool@0x20, slot size = sizeof(Model) = 0xE8 — plus PORT-guarded heap-fallback bumps in model.c), **D54 RESOLVED** (cseq ALCMidiHdr BE header: port-layer `romdataFixupCseq` bswap32 of the first 17 u32s, called from music.c after each decompress), **D54b RESOLVED** (synth param slots sized for ALStartParamAlt = 0x28 in synthesizer.c alSynInit under PORT), **D55 RESOLVED** (RLE folder-menu background BE w/h header: bswap32 of the first word at `(u32 *)&unknown2` at cart-map time in romdataInit, guarded). Build GREEN; game boots, plays intro music, renders through logo/gun-barrel, instantiates Brosnan, and executes the gun-barrel hole DL clean to ENDDL. **D56 RESOLVED** (watch Model/RW-pool raw offsets: field-name Model access + static 0xC8-byte pool under PORT in bondview2.c), **D57 RESOLVED** (pointer-grown rwdata records overflowed N64-sized spare pools — Brosnan PC numRecords 153 > 140: capacities grown in initunk_005520.c + dynamic slot+pool fallback in model.c), **D58 RESOLVED** (gun-barrel DL: vertex-pointer K0 idiom rebuilt via `OS_K0_TO_PHYSICAL(…) | 0x80000000` in title.c + DL reserve 0x100→0x200 because `sizeof(Gfx)` is 16 on PC). **D59–D68 RESOLVED (committed):** the "GL DLL" crash was D64's unbounded blood-RLE write (sentinel section-adjacency lost on PC) clobbering the gun-barrel sub-DL; then D60–D62 (DMA target validation, OSMesgQueue layout), D65/D65b (HEADS/BODIES enum signed sentinels under PORT), D66 (romCopyAligned + ramrom replay 64-bit pointer width), D67 (struct image_entry N64 layout), **D68 (Globalimagetable BE→LE fixup** — `port/src/gimgfixup.c` bswaps IMAGESEG Gfx w1 words + sImageTableEntry.index after texReset's romCopy; compiled globalDL shadows synced for explosion.c). The game now renders the **entire intro** (logo → gun barrel w/ Brosnan → cast; ~frame 2100, ≈2 min wall-clock at the current ~20 fps clean-run rate). **D69 RESOLVED (committed):** `load_bg_file` no longer faults on stage load. BG-file headers/records are N64 big-endian segment-0x0F offsets with internal self-relative offsets; fixed via offline sidecar conversion (`tools_pc/d69_emit.py` → `data/pccg-<region>/pccg.bin` + manifest, same Plan-B pattern as D43/pcmodels, port-layer wiring in `port/src/pccg.c`) plus four ABI layout fixes surfaced along the way: D78 (`StandTile` id/room bitfield packing), D79 (`bg_room_data` pointer-width), D83 (`StandTileHeaderMid`/`Tail` bitfield packing — same class as D78, caused an infinite loop in `stanBuildRoomData` until fixed), D84 (hand-inlined `BG_SEG_TO_PTR`-style folds in room-DL loaders needed the same `(u32)`-cast 32-bit wrap the macro already has). **D85 OPEN, D86/D87 RESOLVED, D88 OPEN (current blocker) — found during/after D69 verification:** D85 — room primary/secondary DL binaries decompress correctly but `texLoadFromGdl` (the already-working model-GDL runtime converter) produces garbage from their content, not yet root-caused; safety-netted (bounds-checked in `bgBuildRoomVtxBounds` so it can't segfault, but geometry is wrong/empty). D86 (RESOLVED) — `modelInitRwData` crash was a single `(int)`-truncated pointer in `initplayergaitobject.c`'s embedded player gait-model init; fixed under `#ifdef PORT`. D87 (RESOLVED) — the front end's genuine attract-mode demo playback crashed on an unswapped big-endian `ramromfilestructure`; fixed with a `#ifdef PORT` byteswap fixup in `ramromreplay.c` (D54-cseq pattern). D88.1–D88.3 (DONE, VERIFIED, uncommitted) — the per-level `Usetup*Z` "stage setup" file (`prop.c`/`struct stagesetup`) is now converted offline by `tools_pc/d88_emit.py` (531 lines; delta-relocates the 8 pointer-widened sub-tables + bswaps s32 ID/offset fields, appended to the same sidecar image; `PCCG_MAX_FILES` 128→256), plus a `SetupIntroCamera` narrow-`u32` `#ifdef PORT` ABI fix (D79/D53.1 class, write-before-read verified). `-level_09` + `GE_D88=1` confirms `proplvreset2` now walks the full pads table correctly; the `prop.c:1306` crash is gone. D88.4 (OPEN, current blocker) — `d88_emit.py` deliberately leaves the `propDefs` polymorphic record stream un-byteswapped; `-level_09` now crashes in `setupDoor` (`prop.c:971`) → `modelLoad` on a garbage big-endian `door->obj`. Needs a per-type byteswap + struct-size audit of the ~40 prop-def record types. See `docs/HANDOFF.md` and `docs/PCPortResearch.md` §F/D88.1-D88.5 for full detail and next steps. **D70–D74 (intro-logo pixels, RESOLVED):** D70 env-gated PPM frame capture (`GE_PCDUMP` → `./ppm/`, gitignored — kept as permanent dev tooling); **D71** C-array texture sources (the four rarewarelogo.c RGBA16 images) byte-swapped on LE PC → port-layer per-source bswap in `import_texture`; **D72** the UV path (GE always uses authored `tc[]` UVs; `lookat_enabled` defaults false); **D73 = root cause of old D72.3** — sinf/cosf `du` double constants are big-endian word pairs, garbage on LE PC → guMtxF2L emitted −32768 for every sin/cos entry → logo triangles projected off-screen; fixed with the PORT-only `DVAL()` macro in `src/libultra/gu/guint.h` (sinf.c/cosf.c `.d` reads replaced; N64 build untouched); **D74** texture import fallback no longer truncates valid gDPLoadBlock data (was dropping letter mip chains + reducing D_02005FF0 to 32×3), `TextureCacheKey` gained `size_bytes`, and the VBO path wraps UVs by tile size for WRAP sub-tiles (N64 semantics). The Rareware logo now renders its four gold letters on the dark-blue plate (PPM-verified ~frame 555; final pixel-perfect check vs N64 footage optional). D69 is resolved; D88.4 is the current crash blocker to a rendered stage frame, with D85 (room geometry) and D75 (front-end 3D model rendering — Nintendo logo mispositioned, gun-barrel Bond model absent, cast-roll character models absent) next after it (see above / §F). Committed through D87. Recurring sub-task: ABI/layout fixes per the D32 procedure (§H) as more asset types are first touched (PD's `preprocess/` module already solves most of them; prefer the offline pattern for format work — D48; full-struct Gfx copies on PC — D50.6; audit struct type-puns after pointer-width changes — D53.2; raw byte offsets into pointer-containing structs shift on PC — D56; N64-sized reservations must be re-checked against 16-byte Gfx/Vtx widths — D58). **Open this session (tracked in §F as D75–D77, lower priority than D69):** D75 3D rendering still wrong (Nintendo logo misplacement + intro player models absent); D76 2D disclaimer screen only partially drawn; D77 no audible music on PC. Prioritization: rendering over audio unless a shared root cause is found (Q1).
- **Phase 3 (audio + input):** libaudio → SDL — largely copy-and-adapt from PD (`mixer.c` 722 lines vs our 31-line stub; `input.c` SDL_GameController backend; §2.4); decide the ASP strategy (C2: `aspMain*` dummies in `ucode.c`).
- **Phase 4 (saves + polish):** file-backed EEPROM — build on PD's `fs.c` (file-backed save dir); PFS/motor already no-op stubs.