mirror of
https://github.com/jkdansereau/goldeneye-pc-port.git
synced 2026-10-23 15:52:42 +02:00
findings.md: has-section dedup, rows 1-10 (D159 D161 D186 D200 D221 D227 D229 D228 D204 D202)
Each cell checked line-by-line against its ## Dxx section(s); cells were compressed summaries of the sections, so rows shrink to one-liner + pointer and status keeps its verdict. Two cells carried facts NEWER than their sections — appended verbatim to the sections first (flagged in-section): - D221: human mouse-playtest confirmation (section still said 'eyeball owed') - D227: M-100b human play-test confirmed (section ended 'still owed') D228's status was the post-split FIX write-up, absent from its pre-fix M-97 section — appended as a second ## D228 pass-section. Exact pre-shrink wording survives in git history + notes/snapshot-pre-ctx-opt/.
This commit is contained in:
1 parent
00a877cc53
commit
45427eaf0e
2 files changed
+22
-12
No files matched your search
@@ -28,23 +28,23 @@ D199,PARTIAL,Phase-3 software audio mixer:,"LANDED (port/src/mixer.c, port/inclu
|
||||
D200,FIXED,-level_09 segfault: reverb's ALDelay.input/output are u32 —,FIXED — 5-line cast in reverb.c (this session)
|
||||
D196,FIXED,"OS mouse cursor stays visible after closing the F10 options overlay in click-to-lock mode (M-49, user playtest).","FIXED (6e758f1d, merged to main) —…"
|
||||
D192,?,Front-end mission/level-select grid pointer still can't reach the outer cells —,"CLOSED — the buggy mode 0 was removed entirely in the v0.2.0 prep pass (see D239); click-to-lock is now the only capture mode, so the unreachable-cells path no longer exists"
|
||||
D221,FIXED,SELECT FILE screen: the mouse hit-box for a file slot is vertically offset from its visible box —,FIXED (M-91) — root cause was NOT a coordinate/origin mismatch:
|
||||
D221,FIXED,SELECT FILE mouse hit-box offset —,"FIXED (M-91) — explicit {min,max} coord2d pairs under #ifdef PORT; human mouse-playtest confirmed."
|
||||
D222,FIXED,High Video.FovScale breaks culling —,"FIXED, awaiting visual verification (M-121)."
|
||||
D223,FIXED,QoL ask: mouse-wheel weapon cycling should be directional like a normal PC shooter —,"FIXED (M-105, port/src/input.c) —…"
|
||||
D224,?,"QoL gap (M-87, from a PD-PC-port survey):","DEPRIORITIZED (M-87, user call)."
|
||||
D225,OPEN,"Dev-tooling QoL (M-87, user ask):","OPEN — root-caused, not implemented."
|
||||
D226,OPEN,"QoL ask: player-adjustable HUD scale for the ammo counter, bottom-left pickup/item status text, and top-of-screen dialogue/subtitle text.","OPEN — root cause / call sites identified, not designed or implemented."
|
||||
D227,FIXED,Sky renders as two independently-moving halves —,"FIXED (M-100b, PR #43) —"
|
||||
D229,FIXED,"Water on IsWater levels renders green and pulses blue<->green on an interval (M-101, user playtest, Frigate -level_26; Surface 2 also an IsWater level).",FIXED (port-layer) — root cause:
|
||||
D229,FIXED,"IsWater-level water renders green, pulses blue<->green (M-101; Frigate -level_26).","FIXED (port-layer) — ZLIB+CI8 water image now imports via the CI8 palette path (gfx_pc.cpp); Frigate verified live (""looks better""); sweep + Surface 2 by-eye still owed."
|
||||
D230,OPEN,In-level music quality:,"OPEN — static-analysis pass done (M-108), not runtime-confirmed."
|
||||
D233,FIXED,All levels (intermittent):,"FIXED (port/fast3d/gfx_pc.cpp, gfx_sp_tri1) —…"
|
||||
D234,FIXED,"Dam: guard towers along the dam structure invisible except the first one (M-106, user QA report).",VISUALLY VERIFIED FIXED (M-108) —…
|
||||
D244,OPEN,Self-hosted CI runner (corpyvt6agent01) link failure:,"OPEN, not yet fixed. Next…"
|
||||
D228,FIXED,AK47 (and other) weapon models still show WHITE missing-texture patches after D217's texpool-alignment fix —,"FIXED (port/fast3d/gfx_pc.cpp, palette_to_rgba32) —"
|
||||
D204,FIXED,PC audio ran ~2 % below real time permanently:,"FIXED (port/src/audio.c, port/src/libultra.c, port/include/audio.h) —"
|
||||
D228,FIXED,AK47 white missing-texture patches after D217's texpool fix —,"FIXED (port/fast3d/gfx_pc.cpp, palette_to_rgba32) —"
|
||||
D204,FIXED,PC audio ran ~2 % below real time permanently (AI feedback loop's 3 ms setpoint vs PC jitter).,"FIXED (port/src/audio.c, port/src/libultra.c, port/include/audio.h) —"
|
||||
D203,?,"Steam Deck (SteamOS, x86_64 Linux) v0.1.0 release bundle:",CLOSED — root cause + fix in D253.
|
||||
D201,FIXED,"src/libultra/audio/bnkf.c bank/instrument/sound/wavetable relocation offsets were s32, truncating the real 64-bit base pointer.",FIXED (src/libultra/audio/bnkf.c) —
|
||||
D202,RESOLVED,"Silenced PPK plays a ""slap"" instead of a gunshot, PLUS user reports broader real-time audio corruption (M-52 → M-59 → REOPENED M-60 → M-61/M-62 closed the data…",ROOT CAUSE ESTABLISHED (M-66); DISPOSITION C IMPLEMENTED + MEASURED (M-66b) —
|
||||
D202,?,"Silenced PPK ""slap"" + broader real-time mixer corruption (M-52→M-67).",ROOT CAUSE ESTABLISHED (M-66); Disposition C implemented + measured (M-66b) —
|
||||
D206,FIXED,PC played every SFX one bank slot too high —,"FIXED (M-76, src/snd.c:1001, #ifdef PORT → soundArray[soundIndex - 1], N64 line verbatim under #else)."
|
||||
D207,PROPOSED,Alarm klaxon starves combat SFX and (per user) doesn't recover after it stops —,MONITORING (M-77c: user reports the alarm is acceptable in play after D206; no fix shipped) —
|
||||
D208,FIXED,Player weapon-fire sound goes permanently silent mid-firefight (all other SFX unaffected) —,FIXED + user playtest-verified (M-78d) —
|
||||
|
||||
|
+17
-7
@@ -412,23 +412,23 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121).
|
||||
| D200 | **`-level_09` segfault: reverb's `ALDelay.input/output` are u32 — `-d->output` zero-extends to a +4GB pointer offset on 64-bit (D3x class, FIXED).** `src/libultrare/audio/reverb.c` back-references the delay ring as `&r->input[-d->output]`; on N64 (s32 `ptrdiff_t`) the u32 negation wraps to a small negative index, on PC x86-64 it zero-extends to +4294967136 samples → `_loadBuffer`/`_saveBuffer` write 13–52KB wild, trampling the delay array / `r->base` / adjacent heap in a self-propagating loop until unmapped memory. Fixed with `(s32)` negation casts at 5 sites (PD ground truth `n_reverb.c` does exactly this); ramalign line gets `(s64)`. Verified: `-level_09` runs 120 s+ crash-free, DRAM guard window over the FX region sees zero OOB writes. | FIXED — 5-line cast in reverb.c (this session) |
|
||||
| D196 | **OS mouse cursor stays visible after closing the F10 options overlay in click-to-lock mode (M-49, user playtest).** — full `## D196` entry at file tail | **FIXED (`6e758f1d`, merged to `main`) —… |
|
||||
| D192 | **Front-end mission/level-select grid pointer still can't reach the outer cells — but only under `Input.MouseCaptureMode=0` (legacy always-grab) (M-49, user…** — full `## D192` entry at file tail | CLOSED — the buggy mode 0 was removed entirely in the v0.2.0 prep pass (see D239); click-to-lock is now the only capture mode, so the unreachable-cells path no longer exists |
|
||||
| D221 | **SELECT FILE screen: the mouse hit-box for a file slot is vertically offset from its visible box — you have to click *below* a file to select it, hovering directly over it doesn't (M-87, user QA, default `MouseCaptureMode=1`).** Different symptom from D192 (D192 is an unreachable-outer-cells *clamp range* bug under legacy mode 0; this is a per-row hit-test/highlight *offset* bug under the shipped default mode 1). | **FIXED (M-91) — root cause was NOT a coordinate/origin mismatch: it's a compiler stack-layout dependency in `interface_menu05_fileselect` (`front.c`).** The hit-test projects each wallet's model extents via `projectRectCornersTo2D`, which takes `{min,max}` `coord2d` *pairs* — but the file-select caller passed `&xmin, &ymin` (four separate f32 locals), relying on the N64 compiler laying out the max adjacent to each min. On PC (declaration-order locals) `arg1->f[1]` reads **ymax** as an X coordinate and `arg2->f[1]` reads an unrelated stack float (observed: `2.25734`, later `nan`) — so the vertical hit band collapsed to a ~14 px strip at the bottom edge of each wallet, sometimes NaN (never selectable that frame). Exactly "click below the file." The other caller (`objective_status.c:525`) passes real `coord2d` structs and was always fine. Fix: pass explicit `{xmin,xmax}`/`{ymin,ymax}` pairs under `#ifdef PORT` (identical values to what the N64 binary used; N64 path untouched). Verified headless: pre-fix A-press at cursor (154.7,127.8) over folder 0 never selected; post-fix same press selects folder 0 and advances. **Human mouse-playtest (this session): confirmed clicking directly over each visible file wallet selects it immediately, no aiming low required; consistent across all slots and the Copy/Erase icons; no crash.** Full details in §H "D221 — M-91". |
|
||||
| D221 | **SELECT FILE mouse hit-box offset — compiler stack-layout dependency, not coordinate mismatch (M-87 QA / M-91 fix).** — full `## D221` entry at file tail | **FIXED (M-91)** — explicit `{min,max}` `coord2d` pairs under `#ifdef PORT`; human mouse-playtest confirmed. Distinct from D192 (mode-0 clamp range, still open). |
|
||||
| D222 | **High `Video.FovScale` breaks culling — NPCs and some world objects stop rendering near the screen edges (M-87, user QA).** — full `## D222` entry at file tail | **FIXED, awaiting visual verification (M-121).** Root cause traced one step further than the original write-up… |
|
||||
| D223 | **QoL ask: mouse-wheel weapon cycling should be directional like a normal PC shooter — wheel up = next weapon, wheel down = previous — instead of both directions…** — full `## D223` entry at file tail | **FIXED (M-105, `port/src/input.c`) —… |
|
||||
| D224 | **QoL gap (M-87, from a PD-PC-port survey): the N64 Rumble Pak is fully dropped instead of modernized.** — full `## D224` entry at file tail | **DEPRIORITIZED (M-87, user call).** Gamepad-only —… |
|
||||
| D225 | **Dev-tooling QoL (M-87, user ask): a debug-build/env toggle that unlocks all missions + all cheats, for testing.** — full `## D225` entry at file tail | **OPEN — root-caused, not implemented.** Plan… |
|
||||
| D226 | **QoL ask: player-adjustable HUD scale for the ammo counter, bottom-left pickup/item status text, and top-of-screen dialogue/subtitle text.** — full `## D226` entry at file tail | **OPEN — root cause / call sites identified, not designed or implemented.** Two viable directions… |
|
||||
| D227 | **Sky renders as two independently-moving halves — reads as "two sky processes" (M-93, user QA on PR #43's debug build, `-level_22` Statue and Cradle).** Each half of the screen shows a different sky pattern, and the two halves scroll/move at different rates relative to each other. Surfaced *while* verifying D176(a)'s perspective-correct-interpolation fix — D176(a)'s fix measurably improved the scroll-speed symptom on the visible pattern but did not touch this; this is a distinct defect, not a regression from that PR (unclear yet whether it pre-dates PR #43 or was merely easier to notice once the scroll speed calmed down enough to see the seam). User flagged one confound worth ruling out first: might be a widescreen/aspect-ratio artifact of rendering at modern resolutions rather than a logic bug — original N64 output is 4:3/{something narrower}, and the sky-quad tiling math (`skyPortRenderPoly`, `sub_GAME_7F097388` upstream) may assume the original screen split. | **FIXED (M-100b, PR #43) — root cause was a unit error, and it also fixed the "sky scrolls too fast" complaint (M-96) and the over-tiling.** `unk20`/`unk24` are already in the RDP's native S10.5 1/32-texel units; M-82 read them as texel counts and baked `tc = (S - fold) * 32`, making every sky texcoord 32x too large and overflowing the `s16` `tc`. Human play-test confirmed by the user on the previously-failing levels. Full write-up: §H "D227 — M-100b". Historical investigation trail below. **OPEN — visual evidence captured + a concrete mechanistic hypothesis found (M-94), not yet fixed.** Headless `-level_22` capture confirms a real, visible crease/discontinuity in the cloud texture — not a rendering artifact of viewing it live, and present in a single static frame (rules out the "just camera pan" explanation for at least this instance). Screenshot: `docs/img/bugs/d227-sky-seam-statue.png`. **Leading hypothesis:** `skyPortRenderPoly` (D176(a)'s fix) computes `wScale` per call — i.e. per individual triangle in the sky fan (`skyRenderTri`/`skyRenderFull` issue up to 5 separate `skyPortRenderPoly` calls per frame from a 5-vertex fan, `sky.c:900-920`/`1372-1393`) — from that triangle's own 3 vertices' `unk0c`. The position math is exact for any `wScale` (verified algebraically: `clip.x = (ndcX·w/wScale)·wScale = ndcX·w` regardless of `wScale`), so this is not a logic bug in the fix itself, but the `s16`-quantized `ob[]` storage means each triangle's shared-edge vertices get **independently re-quantized at a different granularity** depending on that triangle's own `wScale` — a vertex sitting on the seam between two triangles can round to a measurably different `ob[]` value in each triangle's independent call, producing a small position/continuity crack exactly at triangle boundaries. This would read as "two adjacent regions with different patterns" without requiring two draw calls or two cloud layers — one `skyPortRenderPoly` call producing a slightly different quantization per neighboring primitive is sufficient. **Not yet confirmed** — did not isolate camera motion from sky-scroll motion cleanly enough to independently verify the "each half moves at a different rate" part of the user's report, only the static crease. **M-95: FIXED (the static-crease part) + headless-verified.** Implemented the fix direction above: `skyPortBeginFan()`/`skyPortEndFan()` (new, `#ifdef PORT`, `src/game/sky.c`) compute one shared `wScale` across every vertex in the whole fan (`sp274[]`/`sp94[]`, up to 5 verts), called once right after each fan's vertex array is populated and before its 1-3 `skyRenderTri`/`skyRenderFull` calls; `skyPortRenderPoly` now uses that shared value when set, falling back to its old per-call-local computation otherwise (defensive — no other caller exists today, checked: `grep` finds `skyRenderTri`/`skyRenderFull` used nowhere outside this file). **Verified:** same-frame before/after screenshots at `-level_22` frame 345 — `docs/img/bugs/d227-sky-seam-statue.png` (before, visible kink ~x=1000/1280) vs `docs/img/bugs/d227-sky-seam-statue-fixed.png` (after, same frame, continuous streaks, kink gone). Full 21-level `verify.sh sweep`: 21/21 PASS both before and after this change (no regressions). `bunker1`'s `worst_cell` framediff number is unaffected by this change — reproduced identically on the pre-fix build, it's the already-known stale-golden-baseline issue (see M-84/M-83 notes; owed a re-baseline, unrelated to sky.c). **Cradle checked too:** the "black rectangle" artifact visible there is confirmed pre-existing (identical on a pre-fix build capture) — that's the separate, already-documented FOV-coupled black-sky-past-frustum-edge symptom (D218/D222 family), not this defect; didn't chase it here. **Not fully closed:** did not re-verify the "moves at a different rate" half of the original report post-fix (the M-94 addendum's static-camera diff measurement wasn't repeated on the fix); the aspect-ratio-artiLine truncated
|
||||
| D229 | **Water on `IsWater` levels renders green and pulses blue<->green on an interval (M-101, user playtest, Frigate `-level_26`; Surface 2 also an IsWater level).** Reported alongside green weapon textures on Frigate/Surface 2 — **that half was NOT a bug**: the branch under test was 2 commits behind main and those 2 commits were exactly the D217 fixes (#47 texpool alignment, #49 CI cache palette-content key); after merging main the user confirms the gun is good. | **FIXED (port-layer) — root cause: water image is ZLIB+CI8; pool holds raw 8-bit indices; N64's custom ucode expanded them to RGBA16 in TMEM at load, fast3d read index byte-pairs as 16-bit texels (g=2·idx mod 32 dominates → green). Fix: track `src_fmt` per TMEM load; RGBA/16b tile over a CI-sourced slot now imports via the CI8 palette path (`gfx_pc.cpp` import_texture). Frigate verified live (user: "looks better"); sweep + Surface 2 by-eye still owed.** Pre-existing (A/B proven), mechanism identified as above. Built plain `main` with none of the D227 work: `-level_26` frame 340 shows the **same green** (only the tiling density differs), so D229 is independent of D227. The quad is `sky.c`'s `IsWater` block1 (Frigate confirmed `IsWater=1` via `GE_D176` — which also settles M-99's ranked item 1: that path is textured and does go through `skyPortRenderPoly`). Draw state from `sub_GAME_7F09343C` (`unk_092E50.c:278`): tile 0 and tile 1 both RGBA/16b at **the same TMEM 0**, `masks=maskt=5`, tile 1 offset by `gDPSetTileSize(1, uls=90, ult=150, lrs=0, lrt=0)`, 2-cycle `LERP(TEXEL1, TEXEL0, PRIM_LOD_FRAC)` with cycle 2 `= COMBINED * SHADE` and the LOD fraction driven by **`sinf()`** — that sine IS the reported pulsing, so **one texunit resolves blue and the other green** and the sine fades between them. **Ruled out: the shade path** — `skyChooseWaterVtxColour` with measured `env RGB=16,48,96` / `WaterRGB=255,255,150` spans dark blue to pale yellow and can never be green; measured pixels ~`(5,70..175,20..37)` (R and B crushed) put the green on the texel side. **Not established:** why one texunit decodes green when both tiles share TMEM and format. One unproven oddity: `uls/lrs` are `uint16_t` and `width = ((lrs-uls)>>2)+1` gives tile 1 `-22` -> **65514**, though the matching negative `tex_width2` makes the sub-tile-window branch skip and fall through to the correct mask-based 32-texel wrap, so it may be harmless. **Next:** widen the `GE_D172` multitex probe (it filters on `tile1.tmem != tile0.tmem`, equal here, so it never fires) to dump both texunits' decoded state; capture a *sequence* across the sine period, since a single frame is useless (frame 340 reads green on all builds); and check `skywaterimages[2]`'s real format vs the RGBA/16b `sub_GAME_7F09343C` re-declares. **D227 is deliberately decoupled:** M-100b's safety valve takes `allowShift` and the water quad passes FALSE, leaving that path byte-identical to pre-D227 — shifting both tiles was observed live to flatten the cross-fade into constant green. Full write-up: §H "D229 — M-101". |
|
||||
| D227 | **Sky renders as two independently-moving halves — "two sky processes" (M-93 QA; root cause M-100b: unit error, `unk20`/`unk24` are S10.5 not texels).** — full `## D227` entries (M-94→M-100b) at file tail | **FIXED (M-100b, PR #43) — root cause was a unit error, and it also fixed the "sky scrolls too fast" complaint (M-96) and the over-tiling.** `unk20`/`unk24` are already in the RDP's native S10.5 1/32-texel units; M-82 read them as texel counts and baked `tc = (S - fold) * 32`, making every sky texcoord 32x too large and overflowing the `s16` `tc`. Human play-test confirmed by the user on the previously-failing levels. Full write-up: §H "D227 — M-100b". Historical investigation trail below. **OPEN — visual evidence captured + a concrete mechanistic hypothesis found (M-94), not yet fixed.** Headless `-level_22` capture confirms a real, visible crease/discontinuity in the cloud texture — not a rendering artifact of viewing it live, and present in a single static frame (rules out the "just camera pan" explanation for at least this instance). Screenshot: `docs/img/bugs/d227-sky-seam-statue.png`. **Leading hypothesis:** `skyPortRenderPoly` (D176(a)'s fix) computes `wScale` per call — i.e. per individual triangle in the sky fan (`skyRenderTri`/`skyRenderFull` issue up to 5 separate `skyPortRenderPoly` calls per frame from a 5-vertex fan, `sky.c:900-920`/`1372-1393`) — from that triangle's own 3 vertices' `unk0c`. The position math is exact for any `wScale` (verified algebraically: `clip.x = (ndcX·w/wScale)·wScale = ndcX·w` regardless of `wScale`), so this is not a logic bug in the fix itself, but the `s16`-quantized `ob[]` storage means each triangle's shared-edge vertices get **independently re-quantized at a different granularity** depending on that triangle's own `wScale` — a vertex sitting on the seam between two triangles can round to a measurably different `ob[]` value in each triangle's independent call, producing a small position/continuity crack exactly at triangle boundaries. This would read as "two adjacent regions with different patterns" without requiring two draw calls or two cloud layers — one `skyPortRenderPoly` call producing a slightly different quantization per neighboring primitive is sufficient. **Not yet confirmed** — did not isolate camera motion from sky-scroll motion cleanly enough to independently verify the "each half moves at a different rate" part of the user's report, only the static crease. **M-95: FIXED (the static-crease part) + headless-verified.** Implemented the fix direction above: `skyPortBeginFan()`/`skyPortEndFan()` (new, `#ifdef PORT`, `src/game/sky.c`) compute one shared `wScale` across every vertex in the whole fan (`sp274[]`/`sp94[]`, up to 5 verts), called once right after each fan's vertex array is populated and before its 1-3 `skyRenderTri`/`skyRenderFull` calls; `skyPortRenderPoly` now uses that shared value when set, falling back to its old per-call-local computation otherwise (defensive — no other caller exists today, checked: `grep` finds `skyRenderTri`/`skyRenderFull` used nowhere outside this file). **Verified:** same-frame before/after screenshots at `-level_22` frame 345 — `docs/img/bugs/d227-sky-seam-statue.png` (before, visible kink ~x=1000/1280) vs `docs/img/bugs/d227-sky-seam-statue-fixed.png` (after, same frame, continuous streaks, kink gone). Full 21-level `verify.sh sweep`: 21/21 PASS both before and after this change (no regressions). `bunker1`'s `worst_cell` framediff number is unaffected by this change — reproduced identically on the pre-fix build, it's the already-known stale-golden-baseline issue (see M-84/M-83 notes; owed a re-baseline, unrelated to sky.c). **Cradle checked too:** the "black rectangle" artifact visible there is confirmed pre-existing (identical on a pre-fix build capture) — that's the separate, already-documented FOV-coupled black-sky-past-frustum-edge symptom (D218/D222 family), not this defect; didn't chase it here. **Not fully closed:** did not re-verify the "moves at a different rate" half of the original report post-fix (the M-94 addendum's static-camera diff measurement wasn't repeated on the fix); the aspect-ratio-artifact alternate theory was never separately confirmed or ruled out, though the fix visibly closing the crease at a fixed resolution is itself decent evidence the crease specifically was a code-side seam, not a display-scaling artifact. Human eyeball still owed before merge, same as every other rendering fix landed without display access this session. **M-96: human eyeball done — seam/crack STILL PRESENT on Statue with the M-95 fix in.** The static-crease theory (verified by the frame-345 screenshot diff) is therefore not the whole story, or not the dominant contributor to what's actually visible in live play; the never-repeated "moves at a different rate" temporal theory from the original report is the next thing to check — a single-frame diff can't see it. *Line truncated
|
||||
| D229 | **IsWater-level water renders green, pulses blue<->green (M-101; Frigate `-level_26`).** — full `## D229` entry at file tail | **FIXED (port-layer)** — ZLIB+CI8 water image now imports via the CI8 palette path (`gfx_pc.cpp`); Frigate verified live ("looks better"); sweep + Surface 2 by-eye still owed. Full trail in the section. |
|
||||
| D230 | **In-level music quality: a bass instrument sounds corrupted on PC, correct on N64 reference (M-105, user reports; repro refined M-106).** — full `## D230` entry at file tail | **OPEN — static-analysis pass done (M-108), not runtime-confirmed.** Repro… |
|
||||
| D233 | **All levels (intermittent): indoor level geometry invisible near doors — you can see through walls/floors into rooms you can't see into, while world objects…** — full `## D233` entry at file tail | **FIXED (port/fast3d/gfx_pc.cpp, `gfx_sp_tri1`) —… |
|
||||
| D234 | **Dam: guard towers along the dam structure invisible except the first one (M-106, user QA report).** — full `## D234` entry at file tail | **VISUALLY VERIFIED FIXED (M-108) —… |
|
||||
| D244 | **Self-hosted CI runner (`corpyvt6agent01`) link failure: `undefined reference to 'objectiveGetStatus_WEAK'` (2026-09-12, first-ever build attempt on the…** — full `## D244` entry at file tail | **OPEN, not yet fixed.** Next… |
|
||||
| D228 | **AK47 (and other) weapon models still show WHITE missing-texture patches after D217's texpool-alignment fix — a separate failure mode from the green wrong-palette defect (M-97, user playtest of PR #47, `-level_34` FACILITY).** Split out of D217 defect ①, exactly as the M-90 write-up anticipated ("do not close D217 defect ① on this merge — reopen/retitle as the AK47 + NPC-world-model white-texture residual"). **Playtest result that motivates the split:** with PR #47's `texInitPool` 8-byte arena alignment in, the *green* symptom is GONE — PP7/PPK grip and hammer render correct, Bond's watch face correct, no green cast on hands or the 3rd-person world model. But **NPC-held AK47s still render with white patches**, i.e. tiles sampling a missing/undecoded texture rather than a wrong-but-present palette. White ≠ wrong colour: a wrong palette binds a real TLUT with wrong contents (D217's mechanism, now fixed), whereas white is the signature of a texture that never got decoded/uploaded at all, or a tile descriptor pointing at an empty/cleared texpool slot. The M-87 matrix described these as distinct from the start ("AK47 viewmodel has white (missing-texture) patches on the magazine + barrel" vs. the green/blue colour corruption) — this playtest confirms they have distinct root causes, since fixing one left the other untouched. | **FIXED (`port/fast3d/gfx_pc.cpp`, `palette_to_rgba32`) — a real byte-order bug, not a texpool/decode-never-ran issue as originally guessed.** `GE_TEXDUMP` on Facility (`-level_34`) found ~14% of LOD-textured uploads (fmt=CI, `palette_fmt=G_TT_IA16`) rendering solid near-white; a `GE_D228` correlation probe ruled out the texpool/RC2-clip hypothesis (the decoded size exactly matched the tile's base image every time — the data reaches `import_texture` fine, sized correctly). The actual bug: `palette_to_rgba32`'s `G_TT_IA16` branch read `intensity = palentry & 0xff` (low byte) and `alpha = palentry >> 8` (high byte) — backwards relative to the already-correct direct-IA16 decode two functions above it in the same file (`import_texture_ia16`: `intensity = addr[2*i]` (first/high byte after `gfx_dp_load_tlut`'s `PD_BE16` swap), `alpha = addr[2*i+1]`). A dim, fully-opaque palette entry (e.g. intensity=0x58, alpha=0xff) decoded backwards as bright and mostly-transparent (intensity=0xff, alpha=0x58) — exactly the white-patch symptom, on any CI-format material whose TLUT happens to be IA16 rather than RGBA16 (weapon metal/grip materials commonly are, since IA is a natural fit for grayscale metal with a separate opacity channel). Fix: swap the two lines to match the working convention. **User-verified live:** AK47 and other metallic guns render correctly (no more white patches). Verified crash-free with a `-level_34` headless run before the live check; a full 21-level sweep is still owed (not run this session — the user was using their own game instance concurrently, `verify.sh`/`taskkill` would have killed it). D217 · D161 lineage — same general "CI/LUT format-assumption" bug class, distinct specific bug. |
|
||||
| D204 | **PC audio ran ~2 % below real time permanently: GE's AI feedback loop (`src/audi.c:531`) has a ~3 ms setpoint that PC scheduling jitter clears, so the SDL queue starves and the device pads playback with silence (FIXED, measured).** `amMain` wakes at 30 Hz (`sched.c:334` forwards every 2nd retrace to the audio client) and asks for `g_MinFrameSize`=720 samples per block = 21600/s against a 22050 Hz device — structurally 2 % short, relying on 784-sample top-up blocks that `audi.c` only requests once the reported AI length falls under ~69 frames (3 ms). Fine on N64 (double-buffered AI, exact VI interrupt); on PC the queue empties before the loop reacts, and the padded silence is unrecoverable time. **Fix (F5, port-only):** `audioGetAiLengthBytes()` subtracts a 1024-frame (~46 ms) cushion before reporting, so the loop tops up while slack remains; `audi.c`'s control law untouched (rule #2 clean). Measured A/B in one binary via `GE_D204_OLD`: **rt 0.980 → 1.000, q min 0 → 368, drop 0.** Also: F1 correct AI_LEN_REG single-buffer semantics (robustness, measures as a no-op), F3 `Audio.QueueLimit` 8192→2880 + non-silent drops (NB: an existing `ge007.ini` pins it), F4 oversize invariant guard, and `GE_D204=1` cheap audio-health monitor (`rt`/`q`/`drop`/`max`, safe to leave on for a full playtest). **Falsified in-session, do not re-open:** the u32 wrap at `audi.c:531` is real (high-water 2064 frames > the 789 threshold) but harmless — `frameSamples` is `s16` (`audi.c:145`), so it lands negative and audi.c's own lower clamp catches it; max block stays 3136 B vs the 3156 B allocation, no heap overrun. **Corrects two M-63 claims:** `soundIndex=109` is guards' return fire (count was double-logged; the "32.6 ms cadence" is just the 2880-byte block quantum every `dumppos` is rounded to) — closed negative; and M-63's "13 % of real time" was `GE_MIXERTRACE`'s own 25 MB unbuffered log starving the audio thread (same repro without it: 58.0 s / 60 s). Does NOT explain D202. | FIXED (`port/src/audio.c`, `port/src/libultra.c`, `port/include/audio.h`) — measured; a by-ear pass on a real playthrough still owed |
|
||||
| D228 | **AK47 white missing-texture patches after D217's texpool fix — separate failure mode (M-97, `-level_34` FACILITY).** — full `## D228` entries at file tail | **FIXED (`port/fast3d/gfx_pc.cpp`, `palette_to_rgba32`)** — byte-order bug in the G_TT_IA16 branch; user-verified live. Fix write-up: second `## D228` section. |
|
||||
| D204 | **PC audio ran ~2 % below real time permanently (AI feedback loop's 3 ms setpoint vs PC jitter).** — full `## D204` entry at file tail | FIXED (`port/src/audio.c`, `port/src/libultra.c`, `port/include/audio.h`) — measured; a by-ear pass on a real playthrough still owed |
|
||||
| D203 | **Steam Deck (SteamOS, x86_64 Linux) v0.1.0 release bundle: Facility (`-level_34`) crashes "after loading in as James Bond" (user bug report).** — full `## D203` entry at file tail | CLOSED — root cause + fix in D253. |
|
||||
| D201 | **`src/libultra/audio/bnkf.c` bank/instrument/sound/wavetable relocation offsets were `s32`, truncating the real 64-bit base pointer.** — full `## D201` entry at file tail | FIXED (`src/libultra/audio/bnkf.c`) — part of the Phase-3 mixer landing, not yet build/runtime-verified in isolation |
|
||||
| D202 | **Silenced PPK plays a "slap" instead of a gunshot, PLUS user reports broader real-time audio corruption (M-52 → M-59 → REOPENED M-60 → M-61/M-62 closed the data chain, recommended close → REOPENED M-63 on a fuller symptom report).** M-56–M-62: exhaustively verified the index/bank/pointer/decode/ROM-offset/source-data chain — soundIndex 46 is correctly requested and the data is ground truth (byte-match checksum corroboration, M-62). **M-63: user's actual complaint is broader — wrong sound always plays, correct one SOMETIMES plays too (both heard together), and sounds "pile up and spirally glitch out" over a session until only a stuck looping sound (e.g. Bunker's door) remains.** Got a live build+run repro this session (`-level_09`, 60s, `GE_MIXERTRACE`+`GE_AUDIOTRACE`+`GE_AUDIODUMP`, 58 scripted PPK fires). **Ruled out voice-pool exhaustion/leak** — only 16 distinct voice slots used, properly recycled (`sndDeactivate` count tracks `sndPlaySfx` count 1:1). **Found an unexplained anomaly**: `soundIndex=109` (AK47 bolt-action SFX) fires 94 times in 60s despite no AK47 in the repro, some retriggering the same voice slot at a suspiciously uniform ~32.6ms cadence (4-in-a-row) — far faster than plausible weapon fire; looks like something re-issuing `sndPlaySfx` every audio tick instead of once per game event. Not yet confirmed as the cause of the user's symptom, but the top concrete lead. Traces preserved: `scratchpad/d202-m63/`. (Side note, not a real bug: chased a `load_bg_file` crash this session that turned out to be an incomplete test-data setup on the investigator's part — see M-63 write-up.) **M-65 PARTIALLY resolved:** the "eventual silence" cascade is root-caused and mitigated (ownerless `SOUND_FLAG_LOOPED` SFX — sound 203, `METAL_SLIDE_CLOSE_SFX`, `decayTime=-1`, played by `doorPlayCloseSound0/1` with `NULL` owner — leaks 7 of 8 voices; a 4-line guard in the preemption scan reclaims only provably-ownerless loops, measured 171→629 acquisitions), and a second independent cause is fixed (`sndCreatePostEvent` was stubbed out per D138, removing ALL distance attenuation). The audible stuck door loop is still not reproduced — every candidate mechanism ruled out by measurement (see M-65); needs a user capture at the failing door with `GE_AUDIOTRACE=1 GE_AUDIODUMP=1`. | ROOT CAUSE ESTABLISHED (M-66); DISPOSITION C IMPLEMENTED + MEASURED (M-66b) — the audible stuck loop is sound 203 (`METAL_SLIDE_CLOSE_SFX`): ROM infinite ADPCM loop (`count=-1`) + `decayTime=-1`, played fire-and-forget by `doorPlayCloseSound0/1` with NULL owner, never stored in any slot, exempt from preemption (flag 0x12) and from decay-stop scheduling, priority 0x41 makes it unstealable — **faithful N64 behaviour / original quirk, not a port bug**. 327 ms period = -550-cent pitch (keyBase 54 + detune 50 − shift 6000 → ratio 0.7278; 5248 samples @ 22050×0.7278 = 327.007 ms). M-65's guard fires only under pool pressure (twice in the user capture) and cannot silence the idle loop. **Disposition C implemented + measured (M-66b):** PC-only `AL_SNDP_PORT_EXPIRE_EVT` fades provably-ownerless infinite-loop SFX out ~2.5 s after start (2 s delay + 0.5 s fade); per-second spectral check: pre-fix drone flat at max t≈39→361 s, post-fix transient bursts with full silence between; run ends allocated=0/8. **M-67: static analysis exhausted — full-bank data scan clean (all 261), DSP audit complete vs PD, A_LOOP branch dead code in GE, reference clip B00I00S2D.wav REFUTED as an in-game capture (best waveform CC 0.19 ≈ noise; M-61's +0.999 was envelope-only correlation); new `GE_VOICEDUMP` per-voice probe + timestamped WIRE/AUDIOTRACE for the decisive runtime A/B; self-test found the offline resample direction had been inverted all along (y[k]=x[ratio·k]) and that GE "music" is an SFX-sequence system with its own ~8-sample set sharing the 8-voice pool; parked anomaly: sound 232 requested at level start produces no audible audio. **M-68 (user captures ×3): all three complaint classes verified per-voice at runtime — doors CC 0.91–0.99, PPK 46 CC 0.90–0.97, armor 81 full 833 ms vs ROM-predicted 837 ms @ ratio 0.5612; the earlier "instant death" metric was a line-count artifact (µs-timestamped `[EVT]` probe shows every STOP lands on schedule). No port bug: the heard "wrong" sounds are the original design (overlapping SFX, short decays, quick-stop truncation).** **M-69 (full-corpus exact match, 320 scripted-run requests): 286/320 CC ≥ 0.85 — every allocated voice plays the exact ROM sample at the exact ROM pitch; the initial 44 "BAD" were tooling artifacts (voicedump stamps are block-END times; coarse-slide missed sharp onsets; refs not clipped at voice death). Remaining failures = dropped allocations (no `[VOICE+]` — suspected 8-voice pool exhaustion, unverified) + shared-wavetable wire misattribution. No corruption.** **M-70 (decisive clean re-capture, 209 requests, matcher v3): every voiced request Line truncated
|
||||
| D202 | **Silenced PPK "slap" + broader real-time mixer corruption (M-52→M-67).** — full `## D202` entry at file tail | ROOT CAUSE ESTABLISHED (M-66); Disposition C implemented + measured (M-66b) — stuck loop is sound 203, a faithful N64 quirk; PC-side expiration fades it. M-67 static analysis exhausted. Full trail in the section. |
|
||||
| D206 | **PC played every SFX one bank slot too high — a pointer-width layout shift in `struct ALInstrumentAlt_s`, not a game-logic bug (M-76 FIXED).** Root cause of D205 (3) armour + (4) melee→Klobb and of D202's silenced-PPK "slap". `sndPlaySfx` resolves a sound via `soundBank->instArray[0]->soundArray[soundIndex]` (`snd.c:1001`), casting the on-disk standard `ALInstrument` (12-byte u8 header, `s16 bendRange`@12, `s16 soundCount`@14, `ALSound* soundArray[]`@16) through GE's `struct ALInstrumentAlt_s { s32 unk0, unk4, unk8; ALSound *soundArray[1]; }` (`src/snd.h:165`). On N64 (4-byte pointers) that struct's `soundArray` sits at **offset 12** — it deliberately aliases the on-disk `bendRange`/`soundCount` words, so `soundArray[N]` == on-disk table entry **[N-1]**, i.e. GE's `SFX_ID` values are **1-based** into the sound table (`SFX_ID 0 = NOTHING_SFX`, short-circuited at `snd.c:992`, never dereferenced). On PC the 8-byte pointer + 8-byte alignment pushes `soundArray` to **offset 16**, and the converted bank (`port/src/romdata.c` `afFixupInst`, which faithfully reproduces the standard layout) is packed to match — so `soundArray[N]` landed on entry **[N]**, one slot high, on every SFX. Verified by static struct/converter arithmetic **and** at runtime: a BUNKER1 `GE_AUDIOTRACE` capture post-fix shows all ~90 distinct requested indices resolve to `rom_sfx_decode.py` slot **N-1** (0/90 at N). e.g. `ARMOUR_COLLECT_SFX`=81 → slot 80 (= rip `S50`, the user's "correct" armour); `skorpion_stats.Sound`=0x6A=106 → slot 105 (= rip `S69`, "the actual Klobb sound"); `wppksil_stats.Sound`=0x2E=46 → slot 45 (= rip `S2D`, M-61's rejected "+0.999" clip). The earlier "262 enum vs 261 bank ⇒ needs a -1" arithmetic was right about the *symptom*; the *mechanism* is the alias, and `BIG_CLANK_SFX`=261 → slot 260 is in-bounds (never an OOB). Upstream `n64decomp/007` `snd.c` byte-matches with no `-1` and no `NON_MATCHING` guard — correct, because the N64 struct offset supplies the -1. **NOT D205 (2)** explosion→scream (169-183 → slots 168-182, all still explosions) — stays with D205. | **FIXED (M-76, `src/snd.c:1001`, `#ifdef PORT` → `soundArray[soundIndex - 1]`, N64 line verbatim under `#else`).** ABI/layout-only, D3x class (pointer-width struct-layout reconciliation); no game-logic change. Build clean; BUNKER1 60s crash-free; `-level_09` golden framediff 3/3. **User by-ear A/B vs N64 = PASS (M-77c)** — armour / melee / silenced PP7 all correct now → D202 closed, D205 down to symptom (2). Committed `378386d1`. Scratchpad `rom_sfx_decode.py` / `exact_match.py` / `diff_bank.py` still walk slots 0-based — correct for "what is at bank slot i", but a check against a `SFX_ID` must compare to slot `id-1`. |
|
||||
| D207 | **Alarm klaxon starves combat SFX and (per user) doesn't recover after it stops — surfaced by D206 (M-77, ROOT-CAUSED, fix designed not applied).** Before D206, `ALARM3_SFX` (id 163) resolved to the wrong bank slot 163 — a **one-shot** sample: played once, freed its voice. After D206 it correctly resolves to slot 162 = the **real infinite-loop klaxon** (`decayTime=-1` -> `SOUND_FLAG_LOOPED`; ADPCM `loop.count=-1`). Played by `handle_alarm_gas_timer_calldamage()` (`src/game/propobj.c:14457`) with owner `&ptr_alarm_sfx` while `alarmIsActive()`. It now **permanently holds 1 of only 8 SFX voices** (`MUSIC_SFX_SEQ_MAYBE_MAX_SOUNDS=8`, `src/music.c`), at priority `0x41` (looped sounds get `decayTimeFlag + 0x40`, `sndSetupSound` `snd.c:820`) — and is **exempt from the port's preemption scan** (`snd.c` ~369: `!(unk3e & 0x12)` refuses to steal any LOOPED/RETRIGGER voice; the M-65 carve-out only covers *ownerless* loops, and the alarm is owned). **M-77b:** the voice-starvation hypothesis did NOT hold up — a BUNKER1 `GE_FORCEALARM` + scripted-fire soak showed **0 true drops** (`sndDisposeSound` no-voice sites instrumented), the designed last-resort preemption pass **never fired**, and `g_sndAllocatedVoicesCount` recovered to 0 after every alarm-off (no leak). The earlier "~20% drop" was a log-latency artifact. The alarm klaxon (`ALARM3` slot 162) is a *continuous, gapless* infinite loop — a real GE alarm pulses — so the leading remaining explanation is **perceptual** (the drone masking gunfire, and/or slot-162 mixed too loud vs N64), or genuine 8/8 starvation only on a heavy level not yet tested. Needs a user repro. | MONITORING (M-77c: user reports the alarm is acceptable in play after D206; no fix shipped) — **the voice-starvation hypothesis did NOT hold up (M-77b).** The designed last-resort LOOPED-preemption pass was built, and instrumented drop counters (`[D207-DROP]` at both `sndDisposeSound` no-voice sites) + a `[D207-YIELD]` trace were added. Result on BUNKER1 (`GE_FORCEALARM` + scripted sustained fire, ~85 s): **zero true drops**, the last-resort pass **never fired** (pass-1 always found a non-looped victim), and `g_sndAllocatedVoicesCount` sat at 1 during quiet alarm and recovered to **0** after every alarm-off — no leak, no permanent starvation. The earlier "~20% dropped" figure was a measurement artifact (log-line latency, not real drops; every requested sound eventually got a voice via the `unk38` retries). So the fix was **reverted** (kept: nothing in `snd.c`; D206 `-1` only). BUNKER1 combat is too light to peg the 8-voice pool. **Next session needs a real repro from the user:** which level + weapon, and a `GE_AUDIOTRACE=1` capture at the failing alarm — is it (a) genuine 8/8 starvation on a heavy level (Facility/Silo/Statue firefight), (b) a leak that only triggers on a specific alarm-stop path, or (c) perceptual — the continuous klaxon drone masking gunfire / the alarm mixed too loud (check `ALARM3` slot 162 volume vs N64). Temp `GE_FORCEALARM` probe kept in `src/game/propobj.c` for that work. **M-78: re-added just the `[D207-DROP]` counter (NOT the reverted last-resort pass) at both `sndDisposeSound` no-voice sites in `snd.c` (gated on `GE_AUDIOTRACE`), logging `state`/`prio`/`flags`/`count=N/max`, so the user's real-level capture is decisive between (a)/(b)/(c). Static re-check of `ALARM3` slot 162 this session: `sampleVolume=80` (vs gunfire 90-110, punches 100-110 — the klaxon is quieter per-sample, not louder, weakening the "mixed too loud" half of (c)); `decayTime=-1` + `keyMax=8` (`&0xf0=0` → NOT `SOUND_FLAG_RETRIGGER`) → it is a continuous looped sound by design on N64 too, the pulse is baked into the 225→7512-sample ADPCM loop body. So (c) narrows to "the continuous drone masks gunfire" or a loop-point playback defect; (a)/(b) still need the heavy-level capture. Launcher `build-pc/d207_run.ps1` added (forced-alarm auto-repro on level_09).** |
|
||||
| D208 | **Player weapon-fire sound goes permanently silent mid-firefight (all other SFX unaffected) — `struct` field `bondview.h:200 s32 field_A48` is used as a second…** — full `## D208` entry at file tail | FIXED + user playtest-verified (M-78d) — Bunker firefight: player gunshots persist through the whole engagement and survive the klaxon stopping. Committed 7601b9db (PR #29, merged). |
|
||||
@@ -9073,6 +9073,9 @@ that explains every reported symptom, and the user has eyeballed the fixed
|
||||
frame. Also worth re-measuring the scroll rate against M-98's ~7 px/tick
|
||||
baseline: it should now be ~0.2 px/tick.
|
||||
|
||||
**Human play-test (from the §F row, post-M-100b):** confirmed by the user on
|
||||
the previously-failing levels — closes the "still owed" above.
|
||||
|
||||
## D227 — M-100: ROOT CAUSE FOUND AND PROVEN — `s16` texture-coordinate overflow. Not a crack, not view-dependence, not a quantization mismatch. Fix not yet implemented (design decision open).
|
||||
|
||||
**Status: root cause proven by direct measurement + a confirming diagnostic
|
||||
@@ -9886,7 +9889,10 @@ button press on both sides — only the box changed.
|
||||
eyeball owed: normal mouse play through file select (hover highlight,
|
||||
select/copy/delete options) — the headless test proves the hit-test fires
|
||||
where the visible wallet is, but the highlight/selection *feel* is a human
|
||||
check. D192 (mode-0 clamp range) is a separate bug and remains open.
|
||||
check. **Human mouse-playtest (M-91 session, from the §F row):** confirmed
|
||||
clicking directly over each visible file wallet selects it immediately, no
|
||||
aiming low required; consistent across all slots and the Copy/Erase icons;
|
||||
no crash. D192 (mode-0 clamp range) is a separate bug and remains open.
|
||||
|
||||
## D228 — M-97: AK47 white missing-texture patches survive D217's texpool-alignment fix — split out as a distinct defect (white ≠ wrong-colour)
|
||||
|
||||
@@ -10937,3 +10943,7 @@ crash class C2 (Facility `-level_34`, Runway `-level_35`): `import_texture_i8` A
|
||||
**Blood-decal `PointUsage[]` chain — converter now emits it (M-30).** `d43_emit.py` reserved the opcode-0x18 `PointUsage` region in the layout pass (`add_region(puo, 2*nv)`) but the **emit pass never wrote it** — every entry stayed zero. `chr.c`'s decal walk `index = PointUsage[index]` then cycled 0→PointUsage[0]→0 forever (capped by the `#ifdef PORT` guard at `chr.c:3328`, so decals were missing/wrong rather than a true hang). Fix: `op24_pointusage[puo] = nv` in layout + a byteswap loop (`put_s16(remap(puo)+2k, be16(src, puo+2k))` for `nv` = `numVertices` entries — a negative-terminated `s16` index chain, no remap) in the emit pass. Full regen chain re-run, round-trip validation passes. The `chr.c` guard stays as a safety net (SMALL-FIXES B3).
|
||||
|
||||
**Status (from §F table):** FIXED (`tools_pc/d43_emit.py`). Interactive verify pending — blood decals on a BUNKER1 firefight should now appear + no hang.
|
||||
|
||||
## D228 — FIXED: `palette_to_rgba32` G_TT_IA16 byte order (fix write-up from the §F row, appended 2026-09-15 ctx-opt)
|
||||
|
||||
**FIXED (`port/fast3d/gfx_pc.cpp`, `palette_to_rgba32`) — a real byte-order bug, not a texpool/decode-never-ran issue as originally guessed.** `GE_TEXDUMP` on Facility (`-level_34`) found ~14% of LOD-textured uploads (fmt=CI, `palette_fmt=G_TT_IA16`) rendering solid near-white; a `GE_D228` correlation probe ruled out the texpool/RC2-clip hypothesis (the decoded size exactly matched the tile's base image every time — the data reaches `import_texture` fine, sized correctly). The actual bug: `palette_to_rgba32`'s `G_TT_IA16` branch read `intensity = palentry & 0xff` (low byte) and `alpha = palentry >> 8` (high byte) — backwards relative to the already-correct direct-IA16 decode two functions above it in the same file (`import_texture_ia16`: `intensity = addr[2*i]` (first/high byte after `gfx_dp_load_tlut`'s `PD_BE16` swap), `alpha = addr[2*i+1]`). A dim, fully-opaque palette entry (e.g. intensity=0x58, alpha=0xff) decoded backwards as bright and mostly-transparent (intensity=0xff, alpha=0x58) — exactly the white-patch symptom, on any CI-format material whose TLUT happens to be IA16 rather than RGBA16 (weapon metal/grip materials commonly are, since IA is a natural fit for grayscale metal with a separate opacity channel). Fix: swap the two lines to match the working convention. **User-verified live:** AK47 and other metallic guns render correctly (no more white patches). Verified crash-free with a `-level_34` headless run before the live check; a full 21-level sweep is still owed (not run this session — the user was using their own game instance concurrently, `verify.sh`/`taskkill` would have killed it). D217 · D161 lineage — same general "CI/LUT format-assumption" bug class, distinct specific bug.
|
||||
Reference in new issue
Block a user