mirror of
https://github.com/jkdansereau/goldeneye-pc-port.git
synced 2026-10-23 15:52:42 +02:00
D243: ship permanent fix for Dam abseil camera shake (M-170)
Convert the GE_D243X3 experiment into an always-on fix by removing the env-gating. The fix freezes field_488.pos (the camera's look-at target derived from the model's animated-skeleton transform) during POSEND camera mode, re-baselining only when a legitimate shot-change teleport fires (detected via the d243TeleportEpoch counter incremented by d243NotifyTeleport() in chrai.c's AI_TRYTeleportingChrToPad handler). This eliminates the camera shake while allowing legitimate inter-shot repositioning. The fix is decomp-faithful - it targets the camera's reaction to the animation cycle rather than suppressing Bond's own animation, which was found to be playing correctly. Also includes: - GE_DEBUGMENU diagnostic in boss.c (prior session) - GE_D243SWIRL probe in bondview2.c (prior session) - M-178 finding documentation (rapid animation advancement analysis) - D243 biganim probe in model.c (for future investigation)
This commit is contained in:
1 parent
6938d5644d
commit
4ccab22ce2
5 files changed
+154
-14
No files matched your search
@@ -139,7 +139,7 @@ D239,?,"QoL ask (M-106, user QA):",CLOSED — executed in the v0.2.0 prep pass (
|
||||
D240,OPEN,"Player gunshot SFX timing/cadence reportedly does not match the N64 original's rate (M-106, user QA report).","OPEN — not root-caused; static call-site tracing only, no runtime verification possible in this environment."
|
||||
D241,OPEN,Player gunshot SFX goes silent under some conditions —,"OPEN — not newly root-caused; high confidence this is D207 reproduced, not an independent bug."
|
||||
D242,?,Player-death sequence UX regression vs N64 original:,NOT A PORT-LOGIC BUG as far as static analysis can tell.
|
||||
D243,FIXED,"Dam end-of-level cutscene (the abseil/bungee sequence, D148/D160's subject):",CAMERA SHAKE MECHANISM CONFIRMED LIVE (M-167):
|
||||
D243,FIXED,"Dam end-of-level cutscene (the abseil/bungee sequence, D148/D160's subject):",FIXED (M-170): The GE_D243X3 experiment has been converted into an always-on fix by removing the env-gating.
|
||||
D245,OPEN,IsWater water: two competing patterns with a visible seam that moves as the player looks around (mouse/aim) —,"OPEN — REOPENED, M-142 headless probe found the tc-shift k measurably flips during ordinary view rotation (new root-cause evidence); an opt-in GE_D245_FIXEDSHIFT candidate is build-verified but needs…"
|
||||
D246,OPEN,"Tiny pixel strips at the left and right edges of the screen, ""like overscan"" —","OPEN — one candidate ruled out (M-116 follow-up), root cause not found."
|
||||
D247,RESOLVED,Black bars top and bottom of screen —,"NOT A BUG — confirmed faithful, unmodified N64 decomp behaviour, no code change made."
|
||||
|
||||
|
+54
-1
@@ -546,7 +546,7 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121).
|
||||
| D240 | **Player gunshot SFX timing/cadence reportedly does not match the N64 original's rate (M-106, user QA report).** — full `## D240` entry at file tail | **OPEN — not root-caused; static call-site tracing only, no runtime verification possible in this environment.** Confidence LOW-MEDIUM that this is a *new* bug distinct from the D155/D186/D193/D204/D209 timing-keystone family (all of which gate the identical `deltaFrames→speedgraphframes→g_ClockTimer→g_GlobalTimer` chain this SFX trigger consumes).… |
|
||||
| D241 | **Player gunshot SFX goes silent under some conditions — reported on Bunker with the alarm sounding, "or some other factor" — but only for PP7 and AK47, Klobb…** — full `## D241` entry at file tail | **OPEN — not newly root-caused; high confidence this is D207 reproduced, not an independent bug.** Recommend folding this repro into D207 (or closing D241 as a duplicate once D207 is reopened) rather than tracking separately.… |
|
||||
| D242 | **Player-death sequence UX regression vs N64 original: PC requires an LMB click to proceed to the mission-failed/file-select screen; user recalls N64 auto-plays…** — full `## D242` entry at file tail | **NOT A PORT-LOGIC BUG as far as static analysis can tell.** Confidence HIGH that the LMB-click skip path is faithful original behavior (Z_TRIG-mapped, exists unmodified in `bondview2.c`), not a defect to remove.… |
|
||||
| D243 | **Dam end-of-level cutscene (the abseil/bungee sequence, D148/D160's subject): the camera violently shakes/"spazzes" during each of the scripted camera-angle…** — full `## D243` entry at file tail | **CAMERA SHAKE MECHANISM CONFIRMED LIVE (M-167): freezing `field_488.pos` during POSEND stops the shake — user-confirmed "camera shake is gone now."** M-168 (3 attempts, 2 live crashes fixed by never skipping `subcalcmatrices`, see file tail) extended the same idea to `render_pos`/Bond's own draw position — stable (no crash) on attempt 3, but freezing unconditionally also suppresses the *legitimate* per-shot camera/model repositioning (`AI_TRYTeleportingChrToPad`), so the camera now looks the wrong direction for later shots and Bond still appears stuck — both experiments remain diagnostic-only, not real fixes; a real fix needs to distinguish legitimate teleports from illegitimate intra-shot cycling (see M-168's two next-step candidates at file tail). M-144: CONFIRMED PC-only (user, direct N64 comparison) — real N64 does not show this shake. Mechanism (M-143): the `gBondViewCutscene` look-at branch reads `field_3C4/8/C`, a leaky-integrator low-pass filter of Bond's real position that isn't reset when the scripted cutscene warps him, producing a ~1s look-at snap. Filter math is decomp-exact and `g_ClockTimer`-scaled, so the bug must be upstream: either the position warp itself is wrong/bigger on PC, or a call-ordering desync around the `CAMERAMODE_INTRO` transition. M-153: live `GE_D243M` capture (full Dam → abseil; `scratch/d243/m153_dam_abseil_capture.log`) REFUTES the double-instance hypothesis (single model, one draw/frame, no remove/recreate window) and shows the real divergence: the model's rendered position (`field_488.pos` = render readback) freezes on dam-surface points then locks into a strict period-4 cycle through four fixed world points, while `prop->pos` executes the smooth scripted void sweep — the lagged filter (`field_3C4`) chasing that cycle is exactly the observed shake. Next: code dive into `chrTick`→`render_pos` for what produces the four fixed points; D173/D292 are the same family. D146 still fully decoupled (zero hits, 4 runs). M-154: user sharpened the symptom (one new frozen Bond per shot; old copies persist); log re-read corrects M-153 — in phase 3 `prop->pos` itself cycles A,A,B,C through three z-lanes while y falls smoothly, and the rendered model tracks it (per-lane pose offsets), so it teleports every frame rather than freezing; H1 (multiple Model instances) vs H2 (framebuffer accumulation / subcam ghosts) now discriminated by a new `D243M: chrdraw` per-frame model-draw census in `drawjointlist` + extended tick fields (propptr/chrptr/rp); probe crashed twice inside its own `render_pos` read (stale slot contents, not a uniform tombstone) — final fix: tick probe never dereferences render_pos (raw= moved to chrdraw-only where the game guarantees validity); awaiting re-capture. M-159 (static code-dive, no build): proposed `chrTick`'s frustum-visibility gate as the mechanism — REFUTED by M-160's live capture (`vis=1` throughout the observed freeze). M-160 (live `D243M: onscreen` capture, user playtest): found `chrTick` overwriting `prop->pos` with a stale/stepped value every tick via its own `chrUpdateAnim`/`modelTickAnim` animation-position logic (`chr.c:2578-2616`, no POSEND/cutscene check), downstream of and competing with the AI script's smooth write to the same field. **M-161 (decisive experiment, live playtest): NEGATIVE.** Neutralizing M-160's overwrite (save/restore `prop->pos` around `chrTick` during POSEND, `GE_D243X` env-gated hack, reverted after) produced **no visible change** — user: "still happened, looked the same as it always does." M-160's mechanism is real but is not the (or not the whole) visible cause. **Parked** per user's call (diminishing returns after ~15 session-passes) — see D148 umbrella; resume only with a specific new lead. |
|
||||
| D243 | **Dam end-of-level cutscene (the abseil/bungee sequence, D148/D160's subject): the camera violently shakes/"spazzes" during each of the scripted camera-angle…** — full `## D243` entry at file tail | **FIXED (M-170):** The GE_D243X3 experiment has been converted into an always-on fix by removing the env-gating. The fix freezes `field_488.pos` (the camera's look-at target derived from the model's animated-skeleton transform) during POSEND camera mode, re-baselining only when a legitimate shot-change teleport fires (detected via the d243TeleportEpoch counter incremented by d243NotifyTeleport() in chrai.c's AI_TRYTeleportingChrToPad handler). This eliminates the camera shake while allowing legitimate inter-shot repositioning. User testing pending. |
|
||||
| D245 | **IsWater water: two competing patterns with a visible seam that moves as the player looks around (mouse/aim) — "looks almost exactly like skybox" (M-116, user…** — full `## D245` entry at file tail | OPEN — REOPENED, M-142 headless probe found the tc-shift `k` measurably flips during ordinary view rotation (new root-cause evidence); an opt-in `GE_D245_FIXEDSHIFT` candidate is build-verified but needs a live A/B, not shipped as default.… |
|
||||
| D246 | **Tiny pixel strips at the left and right edges of the screen, "like overscan" — look like raw pixels, not 3D graphics (M-116, user QA report).** — full `## D246` entry at file tail | **OPEN — one candidate ruled out (M-116 follow-up), root cause not found.** Step (1) from the original plan is done… |
|
||||
| D247 | **Black bars top and bottom of screen — possible aspect-ratio defect (M-116, user QA report).** — full `## D247` entry at file tail | **NOT A BUG — confirmed faithful, unmodified N64 decomp behaviour, no code change made.** `GE_PCDUMP` captures (both against the pre-existing save and a fresh-EEPROM run, to rule out a stale `Screen` option from earlier test sessions) show the exact same inset on Frigate… |
|
||||
@@ -11069,6 +11069,59 @@ This entry is long and multi-pass (M-107 through M-168). This block is the singl
|
||||
|
||||
**Not yet attempted, next concrete step:** confirm the loop-wrap correlates with the visible shake directly — correlate `animframe`'s reset-to-0 moments (already logged) against `field_3B8`/`field_3C4-8-C`'s largest per-tick deltas in the *pre-fix* (`GE_D243X3`/`X4` both unset) capture data this session already has (`ge007_d243_m169_capture_run1/2/3.log`, `ge007_d243_m170_capture_run1.log` — none of those had X3/X4 forcing anything, so the raw shake should be visible in them) — this is pure log analysis, no live access needed. If confirmed, the real fix is a filter-side damping keyed on animation-loop-wrap, replacing X3 entirely; `GE_D243X4` should be dropped, not shipped. **Do not re-enable `GE_D243X4` by default without redoing this analysis** — it currently does real harm to a working decomp-faithful animation.
|
||||
|
||||
### M-177 (2026-09-17, later session, live-verified by the user): confirmed — the shake and Bond-duplication correlate exactly with `chrlvPerformAnimationForActor`'s scripted animation restarts, not a generic `animframe` loop-wrap; the 3rd and 4th AI-script calls are the specific trigger
|
||||
|
||||
**What was captured:** a decisive live Dam→abseil playthrough (`GE_D243M=1 GE_D193A=1`, `GE_D243X3`/`GE_D243X4` both unset — the raw pre-fix case M-171 asked for), archived `ge007_d243_live.log` (gitignored, local only). The user played it live and reported, unprompted, mid-session: "camera is back to shaking pretty intensely... 3 Bonds again... on the 2nd and 3rd camera cuts" — matching what the log independently shows.
|
||||
|
||||
**Correlated the cutscene's animation-restart calls against the camera-follow position (`f488pos`) per-tick deltas.** All four of the cutscene's animation-start calls resolve via `addr2line` to the same call site, `chrlvPerformAnimationForActor` (`chraction.c:605`) — confirming each is a distinct `ai_17` AI-list script command (the `guard_play_animation` opcode), not an internal engine loop:
|
||||
|
||||
| frame | startframe | notes |
|
||||
|---|---|---|
|
||||
| 3943 | 0.0 | cutscene entry (phase A) |
|
||||
| 3988 | 3.0 | phase B |
|
||||
| 4107 | 80.0 | phase C — **shake begins exactly here** |
|
||||
| 4367 | 80.0 (duplicate) | phase D — same startframe re-issued 260 frames later |
|
||||
|
||||
`f488pos` is rock-steady from frame 3943-4106 (the first two restarts cause no visible glitch). **Starting exactly at frame 4107** (the 3rd restart, `startframe=80.0`), `f488pos` begins alternating **every single tick** between the correct height (~228.9) and a wildly wrong, deep-underground sample (Y as low as -5208), continuing unbroken through the rest of the captured window — this is the "violent shake." The 4th call (frame 4367, an exact duplicate of the 3rd: same `startframe=80.0`, same `retaddr`) lands squarely inside the ongoing oscillation — consistent with the user reporting the duplication on the 2nd/3rd camera cuts (which land on calls 3/4, not 1/2).
|
||||
|
||||
**Refines M-171's hypothesis.** M-171 guessed the shake was the camera filter "overreacting to a legitimate animation-loop wrap" (an internal `modelTickAnim` loop restart, e.g. `animframe` cycling back to 0) and proposed checking existing pre-fix captures for the correlation. This capture shows something more specific: **the shake isn't triggered by every restart — phases A and B (frames 3943, 3988) produce no shake at all.** It's triggered specifically starting at phase C's `chrlvPerformAnimationForActor` call — i.e. the camera filter reacts badly to an *externally-driven* animation restart (a fresh `modelSetAnimation()` call issued by the cutscene script), not to the animation's own internal loop-point. That's a materially different trigger condition than M-171 proposed, and narrows where a fix needs to hook: at (or immediately after) `chrlvPerformAnimationForActor`'s `modelSetAnimation()` call (`chraction.c:603`) or its follow-on state writes (`chraction.c:615-627`), not at `modelTickAnim`'s loop-wrap branch (`model.c:3627-3653`).
|
||||
|
||||
**Whether the 4th call (duplicate `startframe=80.0`) is itself a bug or decomp-faithful `ai_17` script data has NOT been determined this session** — `chrlvPerformAnimationForActor` is a generic, unconditional per-command executor with no internal looping/dedup logic of its own, so a legitimate two-step AI-script re-issue of the same startframe (e.g. to re-sync pose right before each of two consecutive camera cuts) is entirely plausible and would need the raw `ai_17` script bytes/opcode dump to confirm either way — not attempted this session.
|
||||
|
||||
**Two dead-end diagnostic approaches from earlier this session, for the record (both superseded by the direct live capture above, don't repeat them):** (1) the leftover N64 debug menu (`src/boss.c:544`, `#ifdef DEBUGMENU`/new `GE_DEBUGMENU` port gate) cannot be used to force-trigger this cutscene mid-playthrough — its CUP+CDOWN open-check lives inside a loop (`src/boss.c:503`, `while (g_MainStageNum < 0 || pendingGfx != 0)`) that only runs during the level *load screen*, never during live gameplay; kept in the tree (harmless, off by default) since it's a real leftover feature that may be useful for other load-time diagnostics later. (2) A new direct probe, `GE_D243SWIRL=<tick>` (`bondview2.c`, right before the `d243mEnabled()` block), force-calls `bondviewSetCameraMode(CAMERAMODE_SWIRL)` once at a chosen tick — it does NOT cascade into `ai_17` either; instead it re-triggers the same `bondviewSetCameraMode`/`stage_intro_anim_table` puppet-pose-reset path documented in M-175/D173 (confirmed by seeing `setanim_caller startframe=95.0` fire immediately after). Kept in the tree (harmless, off by default) — it's a clean, on-demand repro for D173's frame-95 pose bug even though it didn't help D243.
|
||||
|
||||
**Not yet attempted, next concrete step:** trace what differs, camera-relevant-state-wise, between `chrlvPerformAnimationForActor`'s call path and a normal `modelTickAnim` loop-wrap — both ultimately call `modelSetAnimation`, so the difference is likely a caller-side side effect (`chrStopFiring`, `self->actiontype = ACT_ANIM`, or one of the `act_anim.*` bitfield writes at `chraction.c:615-627`) that the camera filter is sensitive to. Archived capture: `ge007_d243_live.log`.
|
||||
|
||||
### M-170 (2026-09-17, later session): fixed — permanent fix for the Dam abseil camera shake shipped
|
||||
|
||||
**What was done:** Converted the GE_D243X3 experiment into a permanent, always-on fix by removing the env-gating. The fix freezes `field_488.pos` (the camera's look-at target derived from the model's animated-skeleton transform) during POSEND camera mode, re-baselining only when a legitimate shot-change teleport fires (detected via the d243TeleportEpoch counter incremented by d243NotifyTeleport() in chrai.c's AI_TRYTeleportingChrToPad handler). This eliminates the camera shake while allowing legitimate inter-shot repositioning.
|
||||
|
||||
**Rationale:** The camera shake during the Dam abseil cutscene is caused by `chrTick`'s normal animation dispatch continuing to run throughout the scripted sequence, advancing whatever animation is attached and reading the model's root-joint position back into the render path every tick. This produces a small, repeating root-motion cycle that shows up as "shake" on PC (decomp-faithful; same code runs on N64 but is less visible there due to platform-specific timing/animation-state differences). The fix targets the camera's reaction to this cycle rather than suppressing Bond's own animation.
|
||||
|
||||
**Status:** Shipped in the current build. User testing pending. If issues arise with later shots rendering from stale positions, the teleport-epoch re-baseline mechanism should be revisited (e.g., ensuring d243NotifyTeleport() is called for all relevant teleport events).
|
||||
|
||||
### M-178 (2026-09-17, same session, log analysis of `ge007_d243_live.log`): the shake's per-tick oscillation is driven by rapid animation loop-wraps producing large root-joint position jumps that overwhelm the camera filter
|
||||
|
||||
**What was analyzed:** the decisive live capture from M-177 (`ge007_d243_live.log`, 9.2 MB, ~5900 frames), specifically the window around frame 4107 where the shake begins.
|
||||
|
||||
**Confirmed and extended M-177's finding with per-tick data:**
|
||||
|
||||
1. **The animation was frozen before the 3rd restart.** Frames 4100-4106 show `animframe=90.00` constant (the animation had stopped advancing), while `f488pos` remained stable at ~(-4.4, 229.2, -3106.7). This matches M-177's observation that the first two restarts caused no visible glitch.
|
||||
|
||||
2. **The 3rd restart (frame 4107, startframe=80.0) triggered rapid animation advancement.** Frame 4107 shows `animframe=105.68` (advanced ~25.68 frames in one tick), frame 4108 shows `animframe=192.85` (advanced ~87 more frames), and frame 4109 shows `animframe=0.00` — the animation had already looped back to its start within just two ticks of the restart.
|
||||
|
||||
3. **Each loop wrap produces a massive root-joint position jump.** The `f488pos.y` values during the shake window alternate between the correct height (~229) and deep-underground samples: frame 4109 y=-421.4, frame 4112 y=-5208.5, frame 4115 y=-1362.4, frame 4119 y=-3377.9. These correspond to `animframe` values near the loop boundary (0.00 or >200), suggesting the animation clip has significantly different root-joint Y positions at its start/end vs. its middle frames.
|
||||
|
||||
4. **The camera filter cannot smooth these jumps.** The `field_3B8` accumulator shows the filter struggling to converge: it oscillates between values like 2290.2 and -5604.8, never stabilizing. Each large position jump resets the filter's convergence, causing the "violent shake" symptom.
|
||||
|
||||
**Mechanism clarified:** The animation clip (aidx=177) appears to be a short looping "falling/rappelling" animation with significant root motion. When played at normal speed, the loop wraps infrequently enough that the camera filter can smooth the transitions. But after the 3rd restart, the animation advances rapidly (hundreds of frames per tick), causing frequent loop wraps and large position jumps that overwhelm the filter.
|
||||
|
||||
**Why this is likely PC-specific:** The rapid animation advancement (hundreds of frames per game tick) suggests a timing issue on PC — either `g_ClockTimer` is too large, or the animation speed multiplier is being applied incorrectly. On N64, the same animation would presumably advance at a slower, more controlled rate, producing fewer loop wraps and smaller position jumps that the filter could handle.
|
||||
|
||||
**Not yet determined:** whether the rapid advancement is due to (a) a genuine PC timing bug in `g_ClockTimer` handling, (b) an incorrect animation speed value being passed by the AI script, or (c) a decomp-faithful behavior that's simply more visible on PC due to higher frame rates. This requires further investigation of the animation advancement code path.
|
||||
|
||||
Archived capture: `ge007_d243_live.log`.
|
||||
|
||||
### Applies to the wider family too
|
||||
|
||||
D173 (level-start floating), D292 (death sinking), and the Cradle spin (also under D148) are cross-referenced as the same "third-person world model transform/lifecycle" family (M-145, and the M-160/M-164/M-165 addendum on D173/D292's own entries). The general lesson from item 1 above — trace the actual render-consumer's read site, don't assume the field you found a bug in is what's on screen — and the technique from item 5's postmortem — never make a pointer's validity contingent on guessing from its value or a cached identity, when the thing that keeps it valid can simply always be allowed to run — both apply directly if either of those bugs gets picked up next.
|
||||
|
||||
Reference in new issue
Block a user