Files
goldeneye-pc-port/docs/PLAN-M6-playable.md
T
James Dansereau 7bdb19e96f D115: fix gunfire THROW* raw struct player offsets; M-6 D113/D114 findings
D115: THROWMTX/THROWPOS/THROWPREV in gunfire.c were raw byte offsets
((u8*)g_CurrentPlayer + handnum*sizeof(struct hand) + 0xAD8/0xB08/0xB48).
Both the stride (PC sizeof(struct hand) ~0x968 vs N64 0x3B8, D102) and the
base offset are N64-sized, so on x86-64 the address lands inside the
inline gait Model / bondhead-matrix region of struct player and
matrix_4x4_copy(THROWMTX,..) scribbles 64 bytes of live render state on
every casing-ejecting shot. The offsets are exactly
hands[handnum].throw_item_pos_related[_prev] and its translation row -
macros now use those field accessors under #ifdef PORT; N64 build
unchanged. Full survey in docs/AUDIT-M6-player-offsets.md (10 sites,
3 HIGH fixed here, 2 MED open incl. the likely 'weapon model doesn't
draw' cause).

D113 (investigation, no code change): the 'portal-BFS under-reach / void'
premise is stale - the BFS output is correct for BUNKER1's topology
(rooms 26/27 are behind PORTALFLAG_DISABLED closed-door portals, culled
identically on N64). The void is the closed-door models obj 153/154 not
rendering in their doorway -> D114 track.

D114 (investigation, no code change): joint-matrix chain + d43_emit.py
float emission verified clean post-D112; basemtx is a proper
right-handed +Y-up lookat, joint render_pos coherent and upright. All
plan hypotheses disproven. Residual = a horizontal mirror in the shared
port/fast3d viewport / MP-matrix path vs GE's left-handed screen
convention (also explains the open D75 mirrored-text / logo items).
Still open.

Plan + agent reports: docs/PLAN-M6-playable.md. §F: D113/D114/D115.
2026-08-29 09:53:00 -04:00

4.6 KiB
Raw Blame History

Plan — Session M-6: toward a playable, low-glitch BUNKER1 PC build

Baseline: D112 committed (67d674da). Build green. -level_09 renders BUNKER1 continuously, crash-free. Three tracks below, in priority order. Each track: investigate → root-cause → narrow #ifdef PORT fix or write-up per AGENTS.md non-negotiables (no game-logic changes; ABI / layout / format exceptions only, each documented in docs/PCPortResearch.md §F).

Track 1 — Portal-BFS under-reach ("the void") [highest visual impact]

Symptom: in BUNKER storage area (rooms 27–29) the per-frame visible room count collapses to 1–2; large sky-fill void where an adjacent room should show through an open doorway. Portal visibility is otherwise healthy post-D106 (room 18 → 8 rooms deep on enabled doorways).

Known-good / ruled out: currentPlayerGetProjectionMatrix(), g_CurrentPlayer->screensize, the intentional g_RoomLoadBudget 200→3 FP-cam drop, zfar, the plane-side metric cull (bg.c:4135/4144).

Suspects: sub_GAME_7F0B5864 screen-space portal projection (bg.c:1619) — sibling of the D106 z==0 near-plane case, but for partially-off-screen (not straddling) portals; bgQueuePortalTraversal (bg.c:3814/3843) depth/dedup; bgDetermineVisibleRooms (bg.c:4615) seed set; sub_GAME_7F0B5528 clip-point generation (bg.c:1551); transform3Dto2DWithZScaling (bondview.c:730).

Deliverable: root-cause writeup in §F ("D113"); if a narrow PORT fix is obviously correct (e.g. another degenerate-box / clamp mismatch), apply it, else stop and document.

RESULT (Track 1 agent): NOT a portal-BFS bug. The BFS output is correct for BUNKER1's topology — rooms 26/27 sit behind portals 25/26 which carry PORTALFLAG_DISABLED (closed doors), culled identically on N64. Stable 3 visible rooms {29,28,25}, not "1–2". The void is the closed-door prop models (obj 153/154) rendering with a wrong world transform — their leaf DLs are emitted (GE_D96) but land outside the doorway, leaving the wall hole unoccluded → sky. Folds into Track 2 (same model-matrix defect as the inverted guard / mislocated crate). No bg.c change. Probes reverted, tree clean.

Track 2 — Character pose / orientation

Symptom: post-D112 a BUNKER guard renders as a coherent humanoid but appears inverted. Also a mispositioned static crate prop (top-left in the control room).

Known-good: joint rotations from the anim bitstream; render_pos[] positions now sane (~±60 units) after the D112 f32 fix; basemtx from camGetWorldToScreenMtxf() (bondview.c:824) was a clean orthonormal lookat.

Suspects: matrix handedness / lookat sign in the joint base matrix; modelBuildGroupMatrices / process_02_position / subcalcmatrices composition order on LE; a converter sign/axis issue in d43_emit.py group Origin or matrix rodata that survived the D112 fix (byte order right, axis convention wrong); guMtxF2L / Mtxf→Mtx path.

Deliverable: root-cause writeup in §F ("D114"); narrow fix if obviously correct.

Track 3 — struct player raw-offset audit [gate to playability]

Symptom: 1P weapon model doesn't draw. Landmine (§F D100): raw hardcoded-offset accessors into struct player / struct hand are NOT PORT-adjusted and are already PC-wrong.

Known instances: gunfire.c THROWMTX_OFFSET 0xAD8 / THROWPOS 0xB08 / THROWPREV 0xB48 (all g_CurrentPlayer + handoffset + K); plus D102 (weapon Model pool) already fixed.

Task: enumerate every raw byte-offset / hardcoded-size access into struct player, struct hand, and siblings across src/game/ (grep for + 0x, handoffset, (u8 *), hardcoded 0x2A80-class sizes, pointer arithmetic on player). For each: N64 offset vs PC offset (struct is 0x2A8-class larger per D100), whether it's on a BUNKER1-reachable path, severity. Produce a table + recommended fix order. Do NOT fix yet — this is a survey feeding a follow-up.

Deliverable: docs/AUDIT-M6-player-offsets.md table + §F pointer.

Execution

  • Tracks 1, 2, 3 dispatched as parallel investigation subagents (read-mostly; each returns a writeup + optional narrow patch).
  • Integrator (this session) reviews each, applies/adjusts verified narrow fixes, rebuilds (export PATH="/c/msys64/mingw64/bin:$PATH" && ./build-pc.sh ntsc-final), spot-checks -level_09, commits per-track with §F docs.
  • Repro: ./build-pc/ge007.x86_64.exe -level_09 -ml0 -me0 -mgfx100 -mvtx50 -mt700 -ma150. Frame capture: GE_PCDUMP="<range>:<stride>" + tools_pc/pixcount.py / tools_pc/pixcount.py.
  • Sidecar regen (if a converter changes): python tools_pc/d43_emit.py ntsc-final.