WS4 level sweep driven to completion: 12/21 solo levels PASS (load + render + no-crash). Full matrix in docs/LEVEL-STATUS.md, reusable runner tools_pc/level_sweep.sh, WS6 checklist docs/LEVEL-PLAYTEST.md. Fixes: - D123 (tools_pc/d88_propdefs.py): crash class C1 on 6 levels (Dam/Runway/Frigate/Statue/Streets/Cradle). D122 fallout - the widened Vehichle/AircraftRecord.ailist slot was zeroed instead of carrying its read-before-write integer AI-list id, so prop.c -> ailistFindById(0) -> GAILIST_AIM_AT_BOND -> ai() ran a CHR aim list with a NULL chr -> chrIsNotDeadOrShot(NULL). New OBJ_ID_WORDS arm. 4 levels -> PASS, Runway falls through to C2. BUNKER1/Silo unregressed. - D124 (port/src/gimgfixup.c): crash class C2 on Jungle. Compiled explosion-DL pointer-sync keyed on an IMAGESEG marker that texLoad() had already erased -> compiled globalDL_0xNNN arrays kept link-time IMAGESEG words -> 0xABCDxxxx into fast3d on first explosion draw. Latent on every level. Detect the slot from the compiled array instead. Diagnosed, NOT fixed (write-ups in PCPortResearch.md SF): - C2-GDL (D124-Facility addendum): Facility/Runway - model texture-pool path yields a garbage tex->data; every model file loads at an odd bank base (mempAllocBytesInBank does no alignment). Suspect d43_emit.py/pcmodels sidecar texture-blob offsets (N64 8B vs PC 16B Gfx). - C3/C6 (D125): Aztec/Bunker2/Surface2 - converted propDefs blob in RAM doesn't match d88_propdefs.py offline output (garbage after record 0); runtime sizepropdef() walk drifts ~100 records -> wrong door/modelid. d88_propdefs.py convert_stream + sizepropdef() PORT strides verified correct; suspect a dest-offset/pd_end bug in d88_emit.py propdefs emit. Remaining: 9 crashes / 6 classes (C2-GDL, C3/C6, C2m Jungle G_MTX, C5 Control BG portal, C4 Depot BG tile/room, C7 Surface1 sndSetupSound). Priority order in docs/LEVEL-STATUS.md. Also folds in the in-progress docs restructure (HANDOFF/AGENTS/CLAUDE, PCPortResearch D121/D122 SF/SH entries, PLAN-linear-level-sweep, HANDOFF-ARCHIVE, BACKLOG).
9.4 KiB
HANDOFF — GoldenEye 007 PC port (Phase 2, breadth-first level sweep)
Tier 1 doc. Current state + next task + environment. Finding history is
docs/PCPortResearch.md §F/§H (indexed at top of §F); session narrative
is docs/HANDOFF-ARCHIVE.md.
Preflight (do not skip because you have a "next step")
CLAUDE.md(auto) +AGENTS.mdnon-negotiables.- This file, top to bottom.
docs/PORT-LEARNINGS.md— recurring bug classes (you WILL re-derive catalogued bugs otherwise).docs/PLAN-linear-level-sweep.md— the plan of record.- Dispatching a subagent?
docs/AGENT-WORKFLOW.mdfirst — every brief needs FILES / BUDGET / ON-EXPIRY / CONSTRAINTS / REPORT.
Direction (2026-08-29)
Breadth-first pivot. Stop the depth-first BUNKER1 + graphics rabbit-holes. Instead:
- Make boot → intro → menu → level-select functional (not crashing) —
cosmetics parked in
docs/GRAPHICS-BACKLOG.md. - Sweep all 21 solo levels for load + render + no-crash →
docs/LEVEL-STATUS.md.
Full workstream breakdown (WS1–WS6) in docs/PLAN-linear-level-sweep.md.
Where things stand
- BUNKER1 (
-level_09) is playable-ish. Loads, renders recognisably (textured rooms, storage racks, floor; skeletal guards render as humanoids), and survives a guard firefight — 45 s+ crash-free (D103–D120). Silo (-level_20) also loads + renders clean. Committed throughf2beae4b(M-12: D121 WS1 boot, D122 propDef fix). - Input layer (Phase 3) landed and playtested (D118, M-9/M-10).
port/src/input.cis real: keyboard+mouse + SDL_GameController → N64 pad. Core aim/move works. Open polish bugs (deferred): D118a mouse yaw slower than pitch; D118b mouse-Y inverted; rebinding / gamepad hotplug /ge007.inigeneration still TODO. - Recent fixes (M-10,
d1e93b76): D119 guard-attack crash (weapons_held[]->chrtype-pun) fixed; D120 blood-stain hang guarded (not fixed —d43_emit.pyopcode-0x18 converter gap). - Cosmetic backlog (parked,
docs/GRAPHICS-BACKLOG.md): D75 front-end 3D model transforms (Nintendo logo misplaced, gun-barrel Bond absent, cast models absent), D76 disclaimer screen partial, D77 no audio, D114/D116 HUD/text X-mirror (DO NOT re-static-trace — see PORT-LEARNINGS §D2), D74 dead wrap-block.
Done this session (M-12) — 2 commits
- WS1 / D121 (
02c12068) — bare./build-pc/ge007.x86_64.exe -level_XXauto-injects that stage'smemallocstringtable[]-m*pool row (#ifdef PORTinboss.c bossInitMainthreadData). No manual-m*args any more. Gotchas recorded: settingg_DebugAndUpdateStageFlag=1is the WRONG fix (routes boot through the title-stage intro), andtokenSetStringreplaces the whole token buffer so the injected string must carry-level_XXforward. See §H D121. - D88.4 was already resolved (committed
ff563812/4ccc0d3cweeks ago). The "OPEN — cross-level blocker /setupDoorcrash" note in the old §F index / plan was stale.d88_emit.py --regen= 21/21 pass. - D122 (
f2beae4b) — the real cross-level blocker was prop/item model loading.tools_pc/d88_propdefs.pyhad a per-type handler table + a generic fallback; 6inherits ObjectRecordpropDef types (47 TINTED_GLASS, 39 VEHICHLE, 40 AIRCRAFT, 45 TANK, 13 AUTOGUN, 20 AMMO/MultiAmmoCrate) had no handler → fell to the generic word-granularbswap32, which swapped the[s16 obj][s16 pad]word as one u32 → model idobjin the wrong half → OOBPitemZ_entries[]deref → crash inmodelLoad(loadobjectmodel.c:393) /modelInitRwData(model.c:6249). Fixed in the converter (OBJ_TAIL_DESChandler) + matchingsizepropdef()#ifdef PORTstride. BUNKER1/Silo were never affected (they don't emit those types). Full write-up: §F/§H D122. Confidence: crash fix high; types 39/40/45 tail layout medium (structs have "locs unconfirmed" notes — nudge if a level actually drives a tank/vehicle).
Uncommitted docs (tangled with the in-progress big docs restructure —
HANDOFF.md, AGENTS.md, CLAUDE.md): the D121 + D122 entries in
docs/PCPortResearch.md §F/§H and this file's edits. Commit or fold in.
Next task — WS4/WS5: drive the 21-level sweep
WS4 matrix DONE — docs/LEVEL-STATUS.md. 7 / 21 PASS (Bunker1 09,
Silo 20, Archives 24, Train 25, Caverns 39, Egypt 32, Cuba 54). 14 crashes
in 7 classes C1–C7. Reusable sweep runner: tools_pc/level_sweep.sh
(bare -level_XX, GE_PCDUMP="80-260:40", 24 s watchdog,
taskkill //F //IM ge007.x86_64.exe; export PATH=".../mingw64/bin:$PATH"
before addr2line — the script's own symbolication no-op'd without it).
| Class | Levels | Site |
|---|---|---|
| C1 | Dam 33, Runway 35, Frigate 26, Statue 22, Streets 29, Cradle 41 | chrIsNotDeadOrShot chraction.c:4483 — self = AI-list rodata ptr |
| C2 | Facility 34, Jungle 37 | import_texture_i8/gfx_tex_normalize_source — bad tex ptr |
| C3 | Aztec 28, Bunker2 27 | propobj.c door model / linkedDoor walk |
| C4 | Depot 30 | prop.c:902 sp4C->room after walkTilesBetweenPoints |
| C5 | Control 23 | bg.c:5723 portal_pts->numPoints |
| C6 | Surface2 43 | loadobjectmodel.c:393 PitemZ_entries[modelid].header (D122 cont.) |
| C7 | Surface1 36 | snd.c:653 sndSetupSound (audio — parked subsystem) |
Done M-13: C1 fixed (D123, tools_pc/d88_propdefs.py — the C1
crash was D122 fallout: widened Vehichle/AircraftRecord.ailist slot
zeroed instead of carrying its read-before-write int id). C2 split:
Jungle's texture crash fixed (D124, port/src/gimgfixup.c — compiled
explosion-DL sync keyed on an already-erased marker); Facility+Runway
diagnosed (model-GDL relocation misaligns dst, objecthandler_2.c /
texLoadFromGdl, D80/D82/D83 area) — NOT fixed.
Full re-sweep after both: 12 / 21 PASS (docs/LEVEL-STATUS.md).
9 crashes remain in 6 classes: C2 Runway+Facility (model-GDL align —
biggest), C3 Aztec+Bunker2 (docs/BRIEF-C3-C6-prop-model.md),
C2m Jungle (explosion-DL G_MTX), C6 Surface2 (PitemZ modelid),
C5 Control (BG portal), C4 Depot (BG tile/room), C7 Surface1
(sndSetupSound). Priority order + files in docs/LEVEL-STATUS.md "Next".
Uncommitted M-13 edits: tools_pc/d88_propdefs.py, port/src/gimgfixup.c,
§F/§H D123+D124, docs/LEVEL-STATUS.md, docs/LEVEL-PLAYTEST.md,
docs/PORT-LEARNINGS.md, tools_pc/level_sweep.sh, the BRIEF-C* files,
this file. Fold into the docs-restructure commit set.
Re-run tools_pc/level_sweep.sh after each fix; keep -level_09 +
-level_20 green (framediff.py). All-21-PASS → hand the user
docs/LEVEL-PLAYTEST.md for WS6.
Verification per fix: target level boots to ≥1 non-degenerate frame
(tools_pc/pixcount.py > a few %), AND -level_09 + -level_20
unregressed (tools_pc/framediff.py). Regen sidecars after any converter
change: python tools_pc/d43_emit.py ntsc-final && python tools_pc/d69_emit.py ntsc-final && python tools_pc/d88_emit.py ntsc-final --regen.
Parked (do NOT start here): WS2 front-end menu playtest (needs a
human driving; cosmetics D75/D76/D77/D114/D116 all out of scope —
GRAPHICS-BACKLOG.md). Audio (Phase 3), saves (Phase 4).
Environment / build
export PATH="/c/msys64/mingw64/bin:$PATH" && ./build-pc.sh ntsc-final # ~5 s
Run from the repo root, not build-pc/.
- Repro (BUNKER1, skips attract mode):
./build-pc/ge007.x86_64.exe -level_09(per-level-m*pool sizes are now auto-injected — D121/WS1; pass them by hand only to override).boss.c:337decodes-level_XXasd0*10 + d1 - 0x210; LEVELID == the-level_XXnumber. - Sidecar regen (after any converter change;
data/is gitignored):Ifpython tools_pc/d43_emit.py ntsc-final && \ python tools_pc/d69_emit.py ntsc-final && \ python tools_pc/d88_emit.py ntsc-final --regendata/is missing:cp baserom.u.z64 data/ge007.ntsc-final.z64first (see §F "data/deletion + recovery"). - Frame capture:
GE_PCDUMP="<start>-<end>:<stride>"→./ppm/(gitignored). Analyse withtools_pc/pixcount.py(non-black content check) andtools_pc/framediff.py <ppmdir>(structural regression vstools_pc/golden/— the port is NOT frame-deterministic, D117; use--maskfor the HUD, not an exact compare).tools_pc/ppm2bmp.pyto view. - Crashes:
ge007.crash.log(repo root). Symbolicateaddr2line -e build-pc/ge007.x86_64.exe -f -C <pc>(image base0x140000000). Frames past the true chain may be stale (D56). - gdb: launch mode is too slow for timing-dependent faults. Attach
mode is fast:
gdb -batch -x cmds.txt -p <winpid>(<winpid>= 4th column ofps -p <bashpid>; game must already be running, e.g.nohup … &). A hardware watchpoint on a global catches a bad write in < 1 min. - Standalone probe compiles need
-std=c11.
Non-negotiables (full list in AGENTS.md)
- N64 build files (
Makefile,tools/,rsp/,ld/) untouched. - Game logic unmodified except narrow, documented
#ifdef PORTABI/layout/format exceptions — each logged as a Dxx in §F/§H with the N64 line kept verbatim under#else. Anything beyond a narrow, obviously-correct exception: stop and write it up with a confidence rating, don't hack it in. - Prefer an offline sidecar converter (
tools_pc/d*_emit.py, D43/D69/D88 pattern) over a runtime fixup for a whole ROM-asset format.