diff --git a/docs/dev/findings.md b/docs/dev/findings.md index 50220a5c..84b58eef 100644 --- a/docs/dev/findings.md +++ b/docs/dev/findings.md @@ -10458,7 +10458,13 @@ crash class C2 (Facility `-level_34`, Runway `-level_35`): `import_texture_i8` A **M-175 (same session): stopped guessing and instrumented the actual choke point instead — every path that sets the player's `bodyModel` animation funnels through `modelSetAnimation` (`model.c:2857`), so added a probe there (filtered to `model == g_CurrentPlayer->bodyModel`, `#ifdef PORT`) logging `__builtin_return_address(0)`, then resolved the logged addresses with `addr2line` against the built exe. Found the exact call site on the first try this way: `bondviewSetCameraMode`, `bondview2.c:936-942`, inside the `CAMERAMODE_SWIRL` branch's intro-fly-in setup (`bondview2.c:910-957`).** This code reads a **decomp ground-truth table**, `stage_intro_anim_table[]` (`bondview.c:355-365`, zero `#ifdef PORT` anywhere in this call chain — completely unmodified decomp): entry `[0]` is `{PTR_ANIM_extending_left_hand, 95.0, -1.0, 0.02}` — animation **"extending_left_hand"**, **start frame 95.0**, play-to-end, speed **0.02** (near-frozen, a held pose not a moving loop). `PTR_ANIM_extending_left_hand` is confirmed index **61** in `animation_table_ptrs1[]` (`initanitable.c`) — an exact match to the `aidx=61` measured live in M-172 on both Dam and Facility, and the `startframe=95.0`/near-zero speed exactly explains the captured `animframe≈96-97` (a few ticks' worth of playback at 0.02/tick past the 95.0 start) staying essentially flat for the puppet's whole visible lifetime. -**Conclusion: the mechanism setting the puppet's pose is fully decomp-verbatim, not a port-layer bug in the *selection* logic.** If Bond's third-person model genuinely renders ~328 units above ground while playing this specific held pose, the remaining candidates are narrowed to exactly two, both **outside this call site**: **(a)** the `PTR_ANIM_extending_left_hand` clip's own keyframe/root-motion data is mis-decoded for this port at/around frame 95 specifically (an asset-pipeline bug, the same class of investigation D252 used — dump and hand-decode the raw ROM bytes for this one clip's frame-95 root translation and compare against what the port's `model.c` bitstream decoder computes) — bucket (a), ABI/format-class, allowed without sign-off; **or (b)** this is genuinely how the pose looks on real N64 too, and either the *camera's* positioning during this exact swirl segment (not the puppet's) is what's actually different on PC, or the "floating Bond" reports are describing real, original N64 behavior that just looks more jarring on PC's sharper rendering — the "reveal, not regression" pattern this project has hit before (D227, D245). **Distinguishing (a) from (b) needs either real N64 reference footage of this exact moment, or the D252-style raw-byte asset dump — not more source-code tracing; this thread is fully static-exhausted for this session.** +**M-176 (same session, live user comparison against real N64): user directly compared this port's level-start sequence against their memory of real N64's — confirms the float is a genuine divergence, not faithful behavior, and reveals a second, deeper mechanism.** Real N64 (per the user, described in detail): attract screen → flyover camera → after 1-2s, Bond appears **standing on the ground, arms at his side** → ~0.25-0.5s later he **draws his gun and surveils left-to-right** as the camera moves into first-person → control passes to the player. **On this port, per the user's direct observation: Bond is floating from the very first frame his model appears — never grounded, not even briefly.** + +Traced the code this triggered: `chrlvTickBondIntro` (`chraction.c:7663`, also fully decomp-verbatim) is a **second-phase watchdog**, confirming the two-part sequence the user described is genuinely implemented: once the held "extending_left_hand" pose (frame 95, near-frozen) wraps back below frame 86, it switches Bond to `fire_standing_draw_one_handed_weapon_fast` (frames 86→131) — this is almost certainly the "draws his gun and surveils" phase, and fired exactly as expected in a live capture (`chrlvPerformAnimationForActor`, `chraction.c:605`, one hit ~200 ticks after CREATE). **So the two-phase structure matches the user's description — but the FIRST phase (which should show Bond grounded, arms at sides) never visibly looks that way on PC; it's elevated from frame 1.** + +Checked one more concrete candidate (the local-delegate-flagged, previously-dismissed `modelSetAnimTranslationScale`/`pov` theory): `c_item_entries[BODY_Formal_Wear].pov` (`assets/obseg/chr/suitbond/chrModelFileRecord.inc.c`) = **1.058** — a small, plausible-looking decomp constant, not an obvious corruption (compare `propobj.c`'s unrelated `10.438f`/`1.0438f` uses for actual anomalous-looking scale values). If the raw pre-scale root-motion translation.y this port decodes at frame 95 is genuinely ~310 units, ×1.058 ≈ 328 — matching the measured figure almost exactly. This makes `pov` *consistent with* the measured number rather than an obvious smoking gun — it doesn't distinguish "asset decode is wrong" from "asset decode is right and N64 genuinely has ~310 units of raw translation baked into this keyframe" (in which case the scale isn't the bug, whatever produced the ~310 raw value is, or nothing is and N64 shows this too — which the user's direct comparison now argues against). + +**Conclusion (updated after M-176's live comparison): the mechanism setting the puppet's pose is fully decomp-verbatim — not a bug in the *selection* logic — and the user's direct live comparison against real N64 (M-176) rules out theory (b) (genuinely faithful N64 behavior).** Real N64 shows Bond grounded during this exact phase; this port shows him elevated from the first frame. Since the selection code, the table data, and the root-motion computation call (`sub_GAME_7F06D3F4`) are all unmodified decomp, and the scale multiplier applied (`pov=1.058`) is a small, plausible constant rather than an obvious corruption, **the remaining candidate is bucket (a): the `PTR_ANIM_extending_left_hand` clip's own keyframe/root-motion data is mis-decoded for this port at/around frame 95** — an asset-pipeline bug, the same class of investigation D252 used (dump and hand-decode the raw ROM bytes for this one clip's frame-95 root translation, compare against what `model.c`'s bitstream decoder computes at runtime). **This is now the concrete, high-confidence next step — not more source-code tracing, and not a rule-2 sign-off case (bucket (a) is allowed without one). This thread is source-tracing-exhausted for this session; the next session's work is an asset/data-level check.** **M-160/M-164/M-165 (2026-09-17, see D243): the shared mechanism is now understood in much more depth, though still not confirmed as the actual PC/N64 divergence.** D243's investigation this session traced the general pattern this whole family plausibly shares: `chrUpdateAnim` (`chr.c:2398-2424`) doesn't move a puppet's world position directly — it advances whatever animation is currently attached (`modelTickAnim`), then reads the model's root-joint transform back into `prop->pos` via `getsuboffset` (`model.c:684`). When something else (a teleport, a spawn, a death transition) moves the puppet's *logical* position without also resetting/updating its *animation state* to match, the next `chrUpdateAnim` call overwrites the new position with wherever the stale animation's root motion happens to be — producing exactly "floats/sinks/shakes relative to where it should be, in a way that tracks the animation, not the intended position." This is a strong candidate mechanism for D173's level-start float (an animation not yet settled/attached correctly at spawn) and D292's death-sink (the death-pose transition possibly not resetting the model's root anchor the way the collision/death logic expects) — **but D243's own parallel investigation (M-165) found this same mechanism may be entirely decomp-faithful**, with the actual PC-specific divergence being *which phase* of an animation a chr happens to be on at the moment of transition (inherited from real-time-dependent prior gameplay, not deterministic) rather than a code-path difference. **Do not treat this as solved** — it reframes what to look for (an animation-identity/phase mismatch at the transition moment, not a position-write bug per se) and gives a concrete technique (`GE_D193A`'s `aidx=` reverse-resolve + a `model->animframe1` phase read, see D243 M-166) for whoever gets live access to test D173/D292 the same way D243's `GE_D243M`/`GE_D243X2` probes now do.