diff --git a/docs/dev/findings-index.csv b/docs/dev/findings-index.csv index 45206976..13d8d1ca 100644 --- a/docs/dev/findings-index.csv +++ b/docs/dev/findings-index.csv @@ -189,8 +189,8 @@ D308,OPEN,"Occasional z-fighting confirmed on some levels' geometry, general/bro D309,FIXED,Complete non-self-recovering freeze (Windows) returning from Caverns to the intro screen —,FIXED via D310 — user-playtest-confirmed 2026-09-18 (Caverns→intro clean; the spin record itself observed resuming correctly in the post-fix probe log). D310,FIXED,"RULE-2-SIGNOFF: chraiitemsize() mis-sizes 1-byte AI_PRINT records (NUL-scans forward), corrupting AI execution for any list containing an active PRINT —",FIXED — user-playtest-confirmed 2026-09-18 (v2: D311,PARTIAL,Complete freeze in modelSetAnimFrame2WithChrStuff root-motion loop —,"GUARDED (#ifdef PORT, D156-guard extension in the same file) —" -D312,OPEN,"Throwable items (mines, grenades, etc.) can clip through walls in certain spots (user report, v0.3.0 pre-release playtest, 2026-09-18).","OPEN — reported only, not investigated." -D313,OPEN,Bullet impacts do not appear on some walls/surfaces —,"OPEN — reported only, not investigated." +D312,FIXED,"Throwable items (mines, grenades, etc.) can clip through walls in certain spots (user report, v0.3.0 pre-release playtest, 2026-09-18).",FIXED — bgBuildRoomVtxBounds mis-reads the G_VTX vertex count on PC (Gfx_le.dma.par bit-layout shift): +D313,FIXED,Bullet impacts do not appear on some walls/surfaces —,"FIXED — same root cause as D312, merged diagnosis; same one-line fix." D314,OPEN,"F10 menu items flicker randomly/intermittently (reported on the main-menu context, user report, v0.3.0 playtest build, 2026-09-18).",OPEN — confirmed still present post-D316 fix (2026-09-18); user deprioritized chasing it further for now. D315,OPEN,Menu scaling differs between main menu and in-game —,"OPEN — disclosed as a known issue, deferred to v0.3.1 (bigger design question, not a mechanical fix)." D316,FIXED,"Mouse-clicking some menu items glitches and lands on the item below instead (user report, v0.3.0 playtest build, 2026-09-18).",FIXED — root-caused to two compounding bugs (naive mouse->logical mapping ignoring the safe-area crop; asymmetric row hit-test band) in port/src/optionsoverlay.c + port/fast3d/gfx_pc.cpp. diff --git a/docs/dev/findings.md b/docs/dev/findings.md index af094de8..e9403959 100644 --- a/docs/dev/findings.md +++ b/docs/dev/findings.md @@ -597,8 +597,8 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121). | D309 | **Complete non-self-recovering freeze (Windows) returning from Caverns to the intro screen — boss thread spins forever in `ai()` on `m_RunToBondPersistent` via a phantom `GotoNext(lblZero)` created by `chraiitemsize`'s `AI_PRINT` NUL-scan mis-sizing a stringless PRINT record (user report + live GDB diagnosis, 2026-09-18).** — full `## D309` entry at file tail | **FIXED via D310 — user-playtest-confirmed 2026-09-18** (Caverns→intro clean; the spin record itself observed resuming correctly in the post-fix probe log). The teardown-ordering open question (why PC presents the unreachable-Bond state) remains documented but is now harmless. | | D310 | **RULE-2-SIGNOFF: `chraiitemsize()` mis-sizes 1-byte `AI_PRINT` records (NUL-scans forward), corrupting AI execution for any list containing an active PRINT — fixes D309's freeze mechanism and the Caverns standing-still guards (`Stop`+`PRINT("wait")` mis-lands on EndList, re-executed every tick; user report 2026-09-18).** — full `## D310` entry at file tail | **FIXED — user-playtest-confirmed 2026-09-18** (v2: global-list-only sizing via `d310ItemSize`; guards resume, Trevelyan pathing intact, Caverns→intro clean; probe log verified both list classes). PD precedent: PRINT removed, slot 0xAD reassigned. | | D311 | **Complete freeze in `modelSetAnimFrame2WithChrStuff` root-motion loop — D156 guard hole: poisoned `framea` (`model->animframe1`) passes the frameb-only clamp and saturates to a ~3.1e9-iteration spin (Caverns, live GDB diagnosis, 2026-09-18).** — full `## D311` entry at file tail | GUARDED (`#ifdef PORT`, D156-guard extension in the same file) — freeze class neutralized; upstream speed/frame poison source OPEN (level reload clears displaced model state). No AI involvement — distinct from D309/D310. | -| D312 | **Throwable items (mines, grenades, etc.) can clip through walls in certain spots (user report, v0.3.0 pre-release playtest, 2026-09-18).** — full `## D312` entry at file tail | OPEN — reported only, not investigated. Explicitly not for v0.3.0; queued for v0.3.1. | -| D313 | **Bullet impacts do not appear on some walls/surfaces — the projectile appears to pass through them; impacts DO work on some surfaces such as doors/windows (user report, v0.3.0 pre-release playtest, 2026-09-18).** — full `## D313` entry at file tail | OPEN — reported only, not investigated. Explicitly not for v0.3.0; queued for v0.3.1. Possibly related to D312 (same wall class). | +| D312 | **Throwable items (mines, grenades, etc.) can clip through walls in certain spots (user report, v0.3.0 pre-release playtest, 2026-09-18).** — full `## D312` entry at file tail | FIXED — `bgBuildRoomVtxBounds` mis-reads the G_VTX vertex count on PC (`Gfx_le.dma.par` bit-layout shift): n=16 batches collapse to single-point bounds and fail the per-batch AABB pre-test, so their wall triangles are never ray-tested. One-line `#ifdef PORT` fix; verified by repro. | +| D313 | **Bullet impacts do not appear on some walls/surfaces — the projectile appears to pass through them; impacts DO work on some surfaces such as doors/windows (user report, v0.3.0 pre-release playtest, 2026-09-18).** — full `## D313` entry at file tail | FIXED — same root cause as D312, merged diagnosis; same one-line fix. Doors/windows use the separate working `bgTestHitOnObj` path, hence the "surface-dependent" appearance. | | D314 | **F10 menu items flicker randomly/intermittently (reported on the main-menu context, user report, v0.3.0 playtest build, 2026-09-18).** — full `## D314` entry at file tail | OPEN — confirmed still present post-D316 fix (2026-09-18); user deprioritized chasing it further for now. Diagnostic probe (`GE_D314=1`) landed in `optionsOverlayHandleInput()` if revisited. | | D315 | **Menu scaling differs between main menu and in-game — main menu scales OK, in-game menu "seems kinda big sometimes" (user report, v0.3.0 playtest build, 2026-09-18).** — full `## D315` entry at file tail | OPEN — disclosed as a known issue, deferred to v0.3.1 (bigger design question, not a mechanical fix). | | D316 | **Mouse-clicking some menu items glitches and lands on the item below instead (user report, v0.3.0 playtest build, 2026-09-18).** — full `## D316` entry at file tail | FIXED — root-caused to two compounding bugs (naive mouse->logical mapping ignoring the safe-area crop; asymmetric row hit-test band) in `port/src/optionsoverlay.c` + `port/fast3d/gfx_pc.cpp`. Build-verified (golden diff PASS, worst_cell=0); interactive click verification owed. | @@ -11968,16 +11968,31 @@ This confirms the M-160/M-164/M-165 hypothesis (`## D173`'s own consolidated-nex **Status:** GUARDED (freeze class neutralized; upstream poison source OPEN). Disclosed to user in-thread as a D156-guard extension following the already-accepted D156 precedent in this same file; if the project wants formal rule-2 sign-off for `src/game` edits, this is the entry to reference — revert is two small blocks. Cross-refs: D156 (original guard + Facility outro hang), D309/D310 (ruled out for this freeze — no AI involvement). -## D312 — Throwable items (mines, grenades, etc.) can clip through walls in certain spots (user report, v0.3.0 pre-release playtest, 2026-09-18). +## D312 — Throwable items (mines, grenades, etc.) can clip through walls in certain spots (user report, v0.3.0 pre-release playtest, 2026-09-18) — FIXED: `bgBuildRoomVtxBounds` mis-reads the G_VTX vertex count on PC (Gfx_le `dma.par` bit-layout shift), collapsing whole batches of wall geometry out of the collision query (diagnosed + fixed, 2026-09-18). **Reported:** user's last-minute v0.3.0 playtest: thrown/placed throwable items — mines, grenades, "etc." — can pass through wall geometry in certain spots rather than colliding with it. Spot-dependent ("certain spots"), not universal. -**Not investigated.** No diagnosis attempted; nothing below is evidence, only starting pointers for whoever picks it up: -- First fidelity question: does the N64 original collide correctly at the same spots? If yes, this is a port-side divergence (collision-query path); if the ROM does the same thing, it's faithful original behavior and the "fix" bucket changes entirely (rule 2). -- Port-side suspects to check in order: the collision/raycast query shims the port provides for whatever `src/game` calls during throwable flight/settling; whether the affected spots correlate with D249's distant-geometry dropout/culling regions (a culled wall would be invisible AND non-colliding if the collider derives from the same culling state); and the standard §A1 ABI catalogue for any 32-bit-fixed-size struct crossed by the query path. -- Repro ask for the next session: which level(s), which throwable, roughly where (the user's "certain spots" should be pinnable to one or two walls/architectural features). +**Diagnosis (2026-09-18, env-gated probes `GE_D312`/`GE_D312V`, Runaway spawn-area wall):** +- Fidelity confirmed first: the N64 original does NOT clip — this is a port-side divergence (user confirmation + the pipeline below being structurally identical to the working door/window path). +- Both D312 (projectiles) and D313 (bullets) funnel into `bgTestBulletHitBackground` (`propobj.c handles_projectile_motion` bg loop; `chrprop.c` fire path). Doors/windows use the separate, working `bgTestHitOnObj` path — matching the user's "works on doors/windows" symptom exactly. +- Probe run 1: queries during a mine flight DO reach the room (room 14) and even register HITs — but only on floor triangles far ahead of the mine; the wall's triangles are never tested. The per-batch AABB pre-test in `bgTestBulletHitBackground` rejects the batches that own the wall. +- Probe run 2 (`D312B` batch-table dump): room 14 has 37 vertex batches; most have degenerate 1-unit bounds (single vertex), while a few (e.g. the floor batches) have correct extents. The pre-test therefore only ever admits the correctly-bounded batches. +- Probe run 3 (`D312V` per-triangle world-box dump, mirroring `bgTestRayIntersectionInRoom`'s index recovery): the wall geometry EXISTS and is at the right place — batch 35 owns a vertical wall at z=-647 spanning x 510..560, y -59..-23; the mine's fixed-point trajectory crosses it dead-center. So the geometry is fine; only the bounds table is wrong. +- Root cause: `bgBuildRoomVtxBounds` (bg.c) computes the G_VTX vertex count as `((gdl[cmdindex].dma.par >> 4) & 0xf) + 1`. On N64, `Gfx.dma.par` IS the params byte `((n-1)<<4 | v0)`, so that is correct there. The PC shim's `Gfx_le` packs word0 as `(cmd<<24)|(par_byte<<16)|len`, and its `Gdma_le.par` bitfield spans bits 0–23 — i.e. `(par_byte<<16 | len)` — so `(dma.par>>4)&0xf` actually reads the low nibble of `len>>4` (= `n & 0xf`). For n ≤ 15 the builder still reads the whole block (+1 vertex, harmless); for **n = 16** (the most common authored size) it collapses to `numvertices = 1`, and the batch's bounds shrink to a single vertex. The per-batch AABB pre-test then rejects that batch for nearly every ray, so its triangles are never intersected: projectiles pass through those walls (D312) and bullets register no impact on them (D313). Batches with n ≤ 15 keep correct bounds — hence "certain spots", not universal. This is the §A1 struct-layout-driven misread class (raw field alias into a union arm whose bit layout changed in the port shim), same pattern as D154/M-30. -**Status:** OPEN — reported only. Explicitly not for v0.3.0; queued for v0.3.1. Possibly related to D313 (bullet impacts missing on what may be the same wall class). +**Fix:** `src/game/bg.c` `bgBuildRoomVtxBounds`, under `#ifdef PORT`: recover the params byte from bits 16–23 of `words.w0` — `numvertices = (((u32)gdl[cmdindex].words.w0 >> 20) & 0xf) + 1;` — restoring the N64 semantics (the `(n-1)` field). N64 path untouched. Verified by repro: with the fix, the mine-flight queries pre-pass and win batch 35, HITs land exactly on the wall plane (hit z = -647.0 in fixed-point), and `handles_projectile_motion` reports `result=0` (collision) instead of pass-through; pistol shots at the same wall now produce impact decal positions on the wall plane. + +**Status:** FIXED (v0.3.1). Cross-ref: D313 (same root cause, merged diagnosis), D154/M-30 (same §A1 pattern in this file). + +## D313 — Bullet impacts do not appear on some walls/surfaces — the projectile appears to pass through them; impacts DO work on some surfaces such as doors/windows (user report, v0.3.0 pre-release playtest, 2026-09-18) — FIXED: same root cause as D312 (`bgBuildRoomVtxBounds` G_VTX count misread), merged (diagnosed + fixed, 2026-09-18). + +**Reported:** user's last-minute v0.3.0 playtest: firing at some walls/surfaces produces no bullet-impact effect — visually it looks like the projectile goes through them — while other surfaces (doors, windows named specifically) show impacts correctly. So the impact system works; its trigger is surface-dependent. + +**Diagnosis:** merged into D312 — see that entry for the full trace. The bullet path (`chrprop.c` fire → `bgTestBulletHitBackground`) shares the same broken per-batch bounds table: batches whose G_VTX block holds exactly 16 vertices get single-point bounds, fail the AABB pre-test, and their wall triangles are never ray-tested — so no hit is registered and no impact effect spawns. Doors/windows use the separate `bgTestHitOnObj` path (unaffected), which is why impacts worked there. The "surface-dependent" appearance was actually batch-size-dependent. + +**Fix:** same one-line change as D312 (`src/game/bg.c` `bgBuildRoomVtxBounds`, `#ifdef PORT`). Verified: pistol shots at the previously-failing Runaway wall now register hits on the wall plane and spawn impacts. + +**Status:** FIXED (v0.3.1). Cross-refs: D312 (root cause), D172 (impact-effect path, fixed earlier). ## D313 — Bullet impacts do not appear on some walls/surfaces — the projectile appears to pass through them; impacts DO work on some surfaces such as doors/windows (user report, v0.3.0 pre-release playtest, 2026-09-18). diff --git a/docs/porting-notes.md b/docs/porting-notes.md index dc54d271..f8df7af7 100644 --- a/docs/porting-notes.md +++ b/docs/porting-notes.md @@ -283,8 +283,14 @@ expressed in N64 `Gfx`/`Vtx` units is **half-size** on PC. N64-semantics `.dma.par` becomes `((u32)gdl->words.w0 >> 16) & 0xff` on PC; **`gdl->dma.par` gives bits 0-23 (length), and `& 0xf` on it is always 0** because `len == 16*n`. The original D154 port had exactly this bug (vtxoff - forced to 0). Same trap latent in `bgBuildRoomVtxBounds` (`gdl.dma.par>>4&0xf` - reads PC bits 4-7, not N64 bits 20-23; currently tolerated). Rule: for + forced to 0). Same trap in `bgBuildRoomVtxBounds` (`gdl.dma.par>>4&0xf` + reads PC bits 4-7 = `n&0xf`, not N64 bits 20-23 = `n-1`): for n ≤ 15 it + happened to read the whole block (+1 vertex), but for n = 16 (the common + authored size) it collapsed to `numvertices=1` → single-point batch bounds + → the per-batch AABB pre-test in `bgTestBulletHitBackground` rejected the + batch → its wall triangles were never ray-tested: D312 projectile + pass-through + D313 missing bullet impacts (FIXED 2026-09-18, recover the + params byte via `((u32)gdl->words.w0 >> 20) & 0xf`). Rule: for anything but the opcode, extract the bit-field explicitly from `(u32)gdl->words.w0` / `.w1`, don't trust the named `.dma.*` sub-fields. Also: a `words.w0 << k >> m` bit-extract idiom that relied on 32-bit diff --git a/src/game/bg.c b/src/game/bg.c index 93f5130b..bff3d848 100644 --- a/src/game/bg.c +++ b/src/game/bg.c @@ -3122,7 +3122,21 @@ void bgBuildRoomVtxBounds(s32 roomID) points[numpoints].max[i] = -0x8000; } +#ifdef PORT + /* D312: on N64 `dma.par` IS the G_VTX params byte ((n-1)<<4|v0), + * but the PC Gfx_le shim packs w0 = (cmd<<24)|(par<<16)|len and + * Gdma_le.par spans bits 0-23 -- so `(dma.par>>4)&0xf` reads the + * low nibble of len>>4 (= n&0xf), not the (n-1) field. Batches + * with exactly 16 vertices (the common case) collapse to + * numvertices=1: the batch's bounds shrink to a single vertex and + * bgTestBulletHitBackground's per-batch AABB pretest rejects the + * batch for nearly every ray, so its triangles are never tested + * (D312 projectile pass-through / D313 missing bullet impacts). + * Recover the params byte from bits 16-23 of words.w0. */ + numvertices = (((u32)gdl[cmdindex].words.w0 >> 20) & 0xf) + 1; +#else numvertices = ((gdl[cmdindex].dma.par >> 4) & 0xf) + 1; +#endif vtx = (Vtx *)(SEGMENT_OFFSET(gdl[cmdindex].dma.addr) + (u32)vertices); @@ -3813,7 +3827,6 @@ bool bgTestRayIntersectionInRoom(coord3d *from, coord3d *to, coord3d *dir, RoomV return found; } - /** * In order to make bgTestBulletHitBackground match, 4 bytes had to dropped from the regular HitThing struct. * There might be an alternate way of matching this that doesn't require the sub-struct.