mirror of
https://github.com/jkdansereau/goldeneye-pc-port.git
synced 2026-10-23 15:52:42 +02:00
diag(D193): instrument the locomotion / anim-root-motion path
Two #ifdef PORT env-gated probes (default-inert, no golden regression): - GE_D193A (chr.c chrTick): per-wall-second per-chr travel speed + the root-motion scalars (scale / anim_translation_scale / animrate / playspeed / model->speed / g_GlobalTimerDelta). GE_D193A_CHR=<n> narrows to one chrnum. - GE_D193B (model.c sub_GAME_7F06D3F4): rate-limited raw anim-bitstream root-motion decode (joint / mtx base channel / decoded s16 triple / angle / the D32 bitDescriptors+bitStream addrs). Silo + Facility captures: every port-side input to the locomotion math reads nominal -- g_GlobalTimerDelta=2.0, playspeed=1.0, scale=0.1, anim_translation_scale=1.0, and the C in this path is identical to N64 (only the non-firing D156 NaN guards are #ifdef PORT). animrate=0.0 is the default (only set on blended transitions). Patrolling guards travel ~60-99 u/s. GE_D193B shows base=0 / angle=0 on every call. So the divergence is either subtle wrong magnitudes in the decoded bitstream values, or in the pos34 accumulation -- neither visible without an N64-decomp reference trace. Findings D193 + GE-ENV-PROBES updated with the numbers and the next step (build n64decomp/007 with matching logging and diff, or frame-count reference footage). One explicit structural check flagged: ModelSkeleton.Joints (ModelJoint*, 4->8 B) reached via model->obj->Skeleton from D43/D45-converted data. Claude-Session: https://claude.ai/code/session_01U7gyYC3pcatXHhD1kPCgsR
This commit is contained in:
1 parent
7206bf8cc1
commit
25b46e020a
4 files changed
+92
-1
No files matched your search
@@ -43,6 +43,8 @@ Two classes:
|
||||
| `GE_SAVELOG` | `src/game/file.c:46`, `src/game/file2.c:16` (`SAVELOG` macro), `src/boss.c:749`, `src/game/objective_status.c:297,343` | Traces the campaign save/unlock chain (objective completion → `end_of_mission_briefing` → `fileWriteSave` → EEPROM). Used to confirm D157. `g_savelogObjOnce` gates the per-criterion dump to the `bossReturnTitleStage` call. | **live** (strip once a few more level boundaries are playtested) |
|
||||
| `GE_D160` | `src/boss.c:744`, `src/game/bondview2.c:791`, `src/aicommands.def:10055,10181,10236,10242,10247` (all `#ifdef PORT`) | Dam exit-cutscene (D148/D160) diagnostic: trace points in `bossReturnTitleStage`, `bondviewSetCameraMode`, and AI cmds `EndLevel`/`exit_level`/`CameraLookAtBondFromPad`/`CameraSwitch`. **Investigation in progress** — user owes a `GE_D160=1` Dam run. | **live** |
|
||||
| `GE_D193` | `src/game/frametiming.c` (`waitForNextFrame`, `#ifdef PORT`) | Per-wall-second line: `render=` rendered frames, `sim=` sim ticks delivered (Σ of the `deltaFrames`/`g_ClockTimer` fed downstream), `clamped=` frames whose catch-up hit `FRAMETIMING_PORT_MAX_CATCHUP`, `maxraw=` largest pre-clamp delta. Healthy steady state = `render=30 sim=60 clamped=0 maxraw=2` (measured M-80, all levels idle). Use to check whether the wall-clock timer under-advances under real AI load (D193). Cheap; safe for a full playtest. | **live** (D193) |
|
||||
| `GE_D193A` | `src/game/chr.c` (`chrTick` → `d193aSample`, `#ifdef PORT`) | Per-wall-second per-ticked-chr locomotion telemetry (D193): `chr=` chrnum, `act=` ACT_TYPE, `speed=` world-units travelled/s, `gtd=` g_GlobalTimerDelta, then the root-motion scalars `scale` / `xlscale` (anim_translation_scale) / `animrate` / `playspeed` / `mspeed` (model->speed) / `endframe` / `anim` ptr. `GE_D193A_CHR=<n>` restricts to one chrnum. M-80: patrolling guards (act=14) travel ~60–99 u/s on the port; gtd=2.0, playspeed=1.0, scale=0.1, xlscale=1.0, animrate=0.0 (default; only set on blended transitions) — all nominal, so D193 is not in these inputs. Needs an N64-decomp comparison run. | **live** (D193) |
|
||||
| `GE_D193B` | `src/game/model.c` (`sub_GAME_7F06D3F4`, `#ifdef PORT`) | Rate-limited (1/97) raw anim root-motion decode trace (D193): `joint=` / `flip=` / `base=` mtx channel index / `frame=` / `tmp=` decoded s16 translation triple from the anim bitstream / `angle=` / `anim` ptr / `bd=`+`bs=` the D32 u32 bitDescriptors/bitStream addresses / `njoints`. M-80 Facility: `base=0`, `angle=0` **always** (root-motion facing delta never non-zero — top lead), `tmp` ≈ (±small, ~1086 hip-height, ±small). Compare `tmp`/`angle` magnitudes against a clean N64 decomp build of the same anim+frame. | **live** (D193) |
|
||||
| `GE_DTEX` | `port/fast3d/gfx_pc.cpp:1001` | Per-`import_texture` param log (dims / line / size / lod / gen_mipmaps). Used to root-cause RC2 and D159. Kept as an inert diagnostic. | **live** (RC2/RC3 not finished) |
|
||||
| `GE_TEXDUMP` | `port/fast3d/gfx_pc.cpp:1020`, `port/fast3d/gfx_opengl.cpp:700` | PPM dump of every uploaded texture + a `fmt/siz/palfmt/palidx/pal[0..3]` line. Root-caused D161 (Depot ceiling). Kept as an inert diagnostic. | **live** (RC3 not finished) |
|
||||
| `GE_D116` | `port/fast3d/gfx_pc.cpp:1710,2362`, `src/game/textrelated.c:265,541` (cached `ge_d116`) | HUD/text "X-mirror" (D114/D116) vbo/uv trace. **D114/D116 CLOSED — NOT A BUG (M-33/D168): the captures were upside-down, not mirrored.** Probe is now dead scaffolding — strip on the next cleanup pass. | dead (D114/D116 closed) |
|
||||
|
||||
@@ -392,7 +392,7 @@ covers D24–D69; the log continues in §H (D32 procedure, D70–D121).
|
||||
| D189 | **Linux `-fstack-protector` aborts on the decomp's latent stack-buffer overruns (M-48) — FIXED.** Two hit on `-level_09`: (1) `sub_GAME_7F0B1DDC` (`stan.c`) — local `StandTile *tileStack[39]`, bail check `if (cat >= 41)` runs only once per outer iteration so `cat` reaches `40 + pointCount` and the append writes past the end; BUNKER1 prop room-list setup legitimately visits ~40 tiles (confirmed in GDB: 30 valid distinct tile ptrs and climbing; `standTileStart=0x701ae160`, so **not** a pointer-truncation bug — the earlier "blob >4 GiB" triage premise was wrong). (2) `bondviewCalcIntroSwirlCamera` (`bondview2.c`) — `f32 pointbuf[10]` written `[-3 .. 11]` via `&pointbuf[i*3]`, i∈[-1..2]. Both harmless on N64 + the MinGW build (no stack protector); only Ubuntu gcc's `-fstack-protector-strong` default makes them fatal `__stack_chk_fail`. **Fix:** `-fno-stack-protector` globally (`CMakeLists.txt`) to match the N64/MinGW builds, + `tileStack[64]` under `#ifdef PORT` for the one cleanly-bounded case, + `stan.c:2225` link-resolve moved to the D177 `PORT_PTRADD` macro for consistency. A *hardened* Linux build would need the whole overrun class swept. **Verified:** Windows `-level_09` framediff 3/3; Linux `-O2` `-level_09` runs to frame 2100+ no crash. porting-notes.md §C. | FIXED (`CMakeLists.txt`, `src/game/stan.c` `#ifdef PORT`); PR #23 |
|
||||
| D190 | **Linux `-level_45` SIGSEGV at load in `add_ptr_to_objective` (`objective.c:64`) (M-48, open).** `objective_ptrs[objective->menu] = objective;` faults — `objective` wild or `objective->menu` a garbage index → OOB write. Almost certainly the D122/D126/D132 propDef-stride / ROM-serialized-struct-widening family (`struct objective_entry` / the type-23/type-1E setup-text record chain read at the wrong stride on PC). Found in the M-48 Linux level sweep: **5/6 spot-checked levels (`-level_09/20/27/34/37`) load + render fine; `-level_45` is the one failure.** Not a v0.1.0-alpha blocker (alpha is explicitly "expect crashes"). Windows: `-level_45` load status not re-checked this session. | OPEN — not investigated (M-48) |
|
||||
| D191 | **Windows `-O2` release-bundle crash: SIGSEGV in `modelGetNodeRwData` (`src/game/model.c:478`) — the `root->Parent` node-tree walk (M-49, user playtests of the v0.1.0 win64 bundle).** **Two instances, identical fault PC `0x1400801b1`:** (1) fresh save, killed the first guard right after escaping the cell in Bunker ii; (2) Statue (`-level_49`?), right after the Trevelyan meeting cutscene. `ge007.crash.log` (auto-dump; symbols intact in the shipped exe, `addr2line` resolves): PC = `modelGetNodeRwData` at `model.c:478` — the `switch (root->Opcode & 0xff)`, i.e. `root` (a `ModelNode *`) is bad; `addr2line` puts it in the inlined self-recursion at `:532`, so the `while (root->Parent) { root = root->Parent; … }` walk (`model.c:527-540`) handed a garbage node into the recursive call. Instance 1: `Rdx = 0x70267bc000000000` — a `~0x70266xxx` heap address in the **high 32 bits, zero low half** = 32-bit pointer field read as 64-bit (or a byte-swapped `u32` pair). Instance 2: `Rdx = 0`, FAULT ADDR `0x0` — `root` (or `root->Parent`) resolved to NULL. Both: `Rcx=Rdi` = the `~0x7008xxxx`/`~0x7007xxxx` object ptr, `R8 = 0x1d` (29). So the `Parent` chain in some model contains a **truncated or NULL link** — pointer-width / byte-swap family (D3x, D119 `weapons_held[]->chr` type-pun, D122/D126/D132 propDef-stride). NOT weapon-fire-specific — common factor is `modelGetNodeRwData` running on a character/cutscene model whose node tree has a bad `Parent`. Crash logs saved: `scratchpad/crashlogs/`. **Repro aid:** shipped exe has full symbols; `debug-crash.ps1` in the bundle dir runs it under gdb, `GE_D51=1` → `d52rw.log` rwdata-pool trace. The crash.c EBP backtrace breaks immediately (`#01: 0x1d`) — need a real `bt` + `p *root` + `p *Objinst` at the fault. Not yet reproduced under a debugger; no fix. | FIXED + PLAYTEST-VERIFIED (M-79). User replayed Bunker ii (first-guard kill) and Statue (post-Trevelyan cutscene) on the fix build — **both no longer crash** → 21/21 solo levels crash-free (v0.2.0 gate met; Cradle's remaining issue is D193, not a crash). Build clean; bunker1 golden framediff 3/3. **Real gdb backtrace (M-79):** the fault is NOT in the `root->Parent` walk — `root` arrives *already* garbage (`0x70267a9000000000` = a half-word-swapped `u32` `0x70267a90`) from frame #1 `bondviewSelectCuff(model=0x70076808, header=0x700763a0, switchindex=29)`, called from `gunUpdateAndFire(GUNRIGHT)` on the frame the player fires. `bondviewSelectCuff` byte-indexes `header->Switches` (a `ModelNode *` array — **8-byte stride on PC**, widened per D43/D45) with `offset = switchindex << 2` (N64 4-byte stride), so every `base[N]` deref lands mid-slot and yields a misaligned half-pointer that is non-NULL by luck → `modelGetNodeRwData(root=garbage)`. **Exactly the D140 bug class** — D140 fixed the identical pattern in `gunfire.c:1740`; this call site was missed. Fix: PORT-only `offset = switchindex * (s32) sizeof(ModelNode *)`; the `base = (u8*)switches + offset` math and the `#else` N64 line are unchanged. ABI/pointer-width only (D3x class), no game-logic change. The Statue instance (`Rdx=0`, NULL fault addr) is the same site landing on a slot whose bytes read as 0. |
|
||||
| D193 | **NPC AI locomotion is too slow — characters don't move to their destinations at the original game's rate (M-49, user playtest; clarified after the FULL 21-level playthrough — "the biggest overall flaw").** Not (primarily) an animation-playback bug — the *travel speed* of scripted/AI movement is wrong: guards, named NPCs (Trevelyan, Ourumov) and friendlies (Natalya) all take noticeably longer to run/walk to their goal positions than on N64. General, not chr-specific. **Leading hypothesis — the D117/D134/D155/D156 wall-clock-timing family:** `chr.c` / `chrai.c` integrate movement as `pos += speed * g_GlobalTimerDelta` and step sim loops `while (i < g_ClockTimer)` / `-= g_ClockTimer` (`chr.c:1437,1446,1491-1502,1862,2359,2569`; `chrai.c:76`). On the port `osGetCount()` is free-running wall-clock (D117), `g_GlobalTimerDelta`/`g_ClockTimer` are derived from it, and D155's `FRAMETIMING_PORT_MAX_CATCHUP = 6` clamps `nextFrameTime`. If the effective per-second sum of `g_GlobalTimerDelta` (or the `g_ClockTimer` tick count) runs low — quantization, the catch-up clamp biting during normal play, or a units mismatch (`g_JP_GlobalTimerDelta` vs `g_GlobalTimerDelta`, `chr.c:1435/1437`) — every delta-scaled AI motion integrates slow while **player** movement (input-driven per frame) still feels right, which is exactly the reported split. Related: **D170** (Ourumov/Trevelyan "flee" looks wrong — flagged there as possibly the same locomotion-speed issue rather than an AI divergence). Also possible: `chrGoToBond/Chr(SPEED_RUN/WALK/SPRINT)` speed enum → path-follow step, or pathfinding advancing ≤1 waypoint per frame-quantized tick. **Instances seen (M-49 full playthrough):** (a) Facility — the post-scripted-scene beat with Ourumov + the soldier squad: the soldiers **walk in super slowly and take a long time to path into firing positions** before they start shooting (this is regular squad combat AI, not a named-NPC script — good evidence the slowdown is general delta-scaled `chr` locomotion / path-following, not one ailist); (b) the named-NPC flee behaviour on Silo (Ourumov) and Cradle (Trevelyan) — see D170; (c) **Natalya (the escort NPC) always walks really slow** — on every escort level (Bunker ii, Statue, Control, Archives) she trails far behind, forcing the player to wait. Escort follow-AI is the same `chrGoToChr`/path-follow path as (a). **WORST CASE — Cradle (`-level_51`) is "bugged out completely" due to Trevelyan's behaviour (M-49).** The final level is Trevelyan-fleeing-and-scripted end to end (he runs the antenna cradle, climbs, drops to the cradle floor, the helicopter beat); if his locomotion timing / path-following is off he never hits the trigger points and the level's scripted progression stalls or goes haywire. This makes D193 effectively a **can't-properly-finish-the-game** bug, not just cosmetic sluggishness. **Next:** log `g_GlobalTimerDelta` + `g_ClockTimer` per frame during normal play and check the 1-second sum vs the N64's ~60; time a guard's run across a known distance vs reference footage; then watch Trevelyan's chr state / current AI command on Cradle. | OPEN — **steady-state timing keystone MEASURED and the "sim sums low" hypothesis is CONTRADICTED (M-80).** Added a `GE_D193=1` per-wall-second probe in `waitForNextFrame()` (`src/game/frametiming.c`, `#ifdef PORT`, env-gated): logs render frames, sim ticks delivered (= sum of the `deltaFrames` fed to `updateFrameCounters` = sum of `g_ClockTimer`), catch-up clamp hits, and max raw pre-clamp delta. Built ntsc-final, ran `-level_09 / _20 / _27 / _34` idle-after-load, ~20 s each. **Every level, rock-steady: render = 30.0 fps, sim = 60.0 ticks/s, clamped = 0, maxraw = 2.** i.e. each rendered frame carries `g_ClockTimer = 2` and the per-second sum is *exactly* the N64's ~60 — the wall-clock timer is NOT running low in steady state, and `FRAMETIMING_PORT_MAX_CATCHUP` never bites in normal play. VSync on/off made no difference (still 30/60). So the B1 premise ("`g_GlobalTimerDelta`/`g_ClockTimer` sum low over a real second") is wrong for the common case; D193 must come from elsewhere. **Residual quantization risk (not yet observed):** `nextFrameTime = (dt_counts + 387937) / 775875` is integer-rounded per frame with no remainder carry, so a scene that renders at a *steady* rate between 30 and 60 that is not an integer divisor of 60 (e.g. a solid 50 fps → dt≈20 ms → rounds to 1 → sim 50/s, ~17 % slow) would under-advance; the fix there is a fractional accumulator in the `#ifdef PORT` path. But the port renders a hard 30 (software RSP ≈ 60 µs/frame — not GPU-bound; the cap is the `pendingGfx < 2` double-buffer + sched round-trip), so this only matters if a real AI-heavy scripted scene drops into the 20–30 band. **Next (needs input, interactive session):** drive Bond into the Facility Ourumov/squad beat (D193a) and Cradle Trevelyan run with `GE_D193=1` — confirm render/sim hold at 30/60 under real AI loLine truncated
|
||||
| D193 | **NPC AI locomotion is too slow — characters don't move to their destinations at the original game's rate (M-49, user playtest; clarified after the FULL 21-level playthrough — "the biggest overall flaw").** Not (primarily) an animation-playback bug — the *travel speed* of scripted/AI movement is wrong: guards, named NPCs (Trevelyan, Ourumov) and friendlies (Natalya) all take noticeably longer to run/walk to their goal positions than on N64. General, not chr-specific. **Leading hypothesis — the D117/D134/D155/D156 wall-clock-timing family:** `chr.c` / `chrai.c` integrate movement as `pos += speed * g_GlobalTimerDelta` and step sim loops `while (i < g_ClockTimer)` / `-= g_ClockTimer` (`chr.c:1437,1446,1491-1502,1862,2359,2569`; `chrai.c:76`). On the port `osGetCount()` is free-running wall-clock (D117), `g_GlobalTimerDelta`/`g_ClockTimer` are derived from it, and D155's `FRAMETIMING_PORT_MAX_CATCHUP = 6` clamps `nextFrameTime`. If the effective per-second sum of `g_GlobalTimerDelta` (or the `g_ClockTimer` tick count) runs low — quantization, the catch-up clamp biting during normal play, or a units mismatch (`g_JP_GlobalTimerDelta` vs `g_GlobalTimerDelta`, `chr.c:1435/1437`) — every delta-scaled AI motion integrates slow while **player** movement (input-driven per frame) still feels right, which is exactly the reported split. Related: **D170** (Ourumov/Trevelyan "flee" looks wrong — flagged there as possibly the same locomotion-speed issue rather than an AI divergence). Also possible: `chrGoToBond/Chr(SPEED_RUN/WALK/SPRINT)` speed enum → path-follow step, or pathfinding advancing ≤1 waypoint per frame-quantized tick. **Instances seen (M-49 full playthrough):** (a) Facility — the post-scripted-scene beat with Ourumov + the soldier squad: the soldiers **walk in super slowly and take a long time to path into firing positions** before they start shooting (this is regular squad combat AI, not a named-NPC script — good evidence the slowdown is general delta-scaled `chr` locomotion / path-following, not one ailist); (b) the named-NPC flee behaviour on Silo (Ourumov) and Cradle (Trevelyan) — see D170; (c) **Natalya (the escort NPC) always walks really slow** — on every escort level (Bunker ii, Statue, Control, Archives) she trails far behind, forcing the player to wait. Escort follow-AI is the same `chrGoToChr`/path-follow path as (a). **WORST CASE — Cradle (`-level_51`) is "bugged out completely" due to Trevelyan's behaviour (M-49).** The final level is Trevelyan-fleeing-and-scripted end to end (he runs the antenna cradle, climbs, drops to the cradle floor, the helicopter beat); if his locomotion timing / path-following is off he never hits the trigger points and the level's scripted progression stalls or goes haywire. This makes D193 effectively a **can't-properly-finish-the-game** bug, not just cosmetic sluggishness. **Next:** log `g_GlobalTimerDelta` + `g_ClockTimer` per frame during normal play and check the 1-second sum vs the N64's ~60; time a guard's run across a known distance vs reference footage; then watch Trevelyan's chr state / current AI command on Cradle. | OPEN — **steady-state timing keystone MEASURED and the "sim sums low" hypothesis is CONTRADICTED (M-80).** Added a `GE_D193=1` per-wall-second probe in `waitForNextFrame()` (`src/game/frametiming.c`, `#ifdef PORT`, env-gated): logs render frames, sim ticks delivered (= sum of the `deltaFrames` fed to `updateFrameCounters` = sum of `g_ClockTimer`), catch-up clamp hits, and max raw pre-clamp delta. Built ntsc-final, ran `-level_09 / _20 / _27 / _34` idle-after-load, ~20 s each. **Every level, rock-steady: render = 30.0 fps, sim = 60.0 ticks/s, clamped = 0, maxraw = 2.** i.e. each rendered frame carries `g_ClockTimer = 2` and the per-second sum is *exactly* the N64's ~60 — the wall-clock timer is NOT running low in steady state, and `FRAMETIMING_PORT_MAX_CATCHUP` never bites in normal play. VSync on/off made no difference (still 30/60). So the B1 premise ("`g_GlobalTimerDelta`/`g_ClockTimer` sum low over a real second") is wrong for the common case; D193 must come from elsewhere. **Residual quantization risk (not yet observed):** `nextFrameTime = (dt_counts + 387937) / 775875` is integer-rounded per frame with no remainder carry, so a scene that renders at a *steady* rate between 30 and 60 that is not an integer divisor of 60 (e.g. a solid 50 fps → dt≈20 ms → rounds to 1 → sim 50/s, ~17 % slow) would under-advance; the fix there is a fractional accumulator in the `#ifdef PORT` path. But the port renders a hard 30 (software RSP ≈ 60 µs/frame — not GPU-bound; the cap is the `pendingGfx < 2` double-buffer + sched round-trip), so this only matters if a real AI-heavy scripted scene drops into the 20–30 band. **Next (needs input, interactive session):** drive Bond into the Facility Ourumov/squad beat (D193a) and Cradle Trevelyan run with `GE_D193=1` — confirm render/sim hold at 30/60 under real AI loLine truncated
|
||||
| D194 | **Mouse input needs another tuning pass — RMB aim over-sensitive + sensitivity couples to frame/sim rate (M-49, user playtest).** Two parts. **(a) Aim mode (RMB) is near bang-bang, not proportional** (`port/src/input.c:697-707`): any per-poll delta past `AIM_MOVE_THRESH` emits stick `m = clamp(61 + |Δ|·(MouseAimSpeed/100)·AIM_GAIN, 61, 60+AimBand)` = `[61,80]` — with the M-29 defaults (`MouseAimSpeed=16`, `AIM_GAIN=4.0`, `AimBand=20`) `m` is already 61 (fast) at ~1.5 px/poll and saturates at 80 by ~30 px/poll, so the usable proportional band is tiny and sits near the top of GE's aim range → "way too sensitive," turn rate barely tracks how fast you actually move the mouse. Needs a real response curve (low floor, wider proportional band, maybe a gamma), not a threshold+clamp. **(b) Overall sensitivity correlates with movement/frame rate** (user's words: "correlated with movement speed, does not feel good"): `input.c` emits raw stick counts **per controller poll** with no `g_GlobalTimerDelta` / polls-per-frame normalization (hipfire yaw `sx += edx·(MouseTurnSpeed/100)·6.0` at `:709`; aim as above). GE integrates the stick scaled by its sim delta, and the port's poll cadence vs render/sim cadence drifts with scene load — so effective sensitivity shifts when the framerate does (which reads as "when I'm moving"). Fix direction: accumulate mouse delta and convert to stick using a fixed reference dt (or feed the game a dt-consistent value), so a given hand motion = a given view rotation regardless of fps. Lineage: D118a (hipfire pitch digital vs analog), D165 (menu pointer), D166 (hipfire pitch pulses), D180-B3 (`MouseAimSpeed` 25→16). Config knobs exist (`Input.MouseAimSpeed/AimBand/MouseTurnSpeed/HipfirePitchSpeed`) but the *shape* of the mapping is the problem. | OPEN — root-caused, not fixed (M-49) |
|
||||
| D195 | **Transparency / alpha surfaces broken on Control (M-49, user playtest)** — Natalya's console room, the glass partitions + translucent projected wall displays. Failure mode not yet specified by the reporter (no `GE_PCDUMP` capture taken). Likely a fast3d render-mode / alpha-blend path defect, not a decode one — neighbours D161 (CI8/LUT decode), D172, D176(b) (both blend-adjacent) but those are texture-format bugs, this reads as a blend-state one; check D128 portal adjacency in case the glass geometry is portal-culled wrong instead. Logged in `GRAPHICS-BACKLOG.md`. **Next:** `GE_PCDUMP` capture on Control near the console room, compare RDP render-mode words against N64 `gmain.s` for the glass/display materials. | OPEN — not investigated (M-49), needs a capture |
|
||||
| D197 | **Character face/head textures wrap around the head, seen on Silo (M-49, user playtest).** Reads as `G_TX_CLAMP` not honoured (or a non-power-of-two wrap period) on a head/face texture tile — the texture repeats around the mesh instead of clamping at the UV edge. Not yet isolated to a specific character or texture; no `GE_PCDUMP`/`GE_TEXDUMP` capture taken. Likely fast3d texture-tile setup (clamp/wrap mode bits from the tile descriptor not round-tripped) rather than a data bug, given it's cosmetic and geometry-independent. **Next:** `GE_TEXDUMP` the offending head texture's tile descriptor on Silo, diff clamp/mirror bits against `gmain.s`'s expectations for that material. | OPEN — not investigated (M-49), needs a capture |
|
||||
|
||||
@@ -33,6 +33,64 @@
|
||||
#include "model.h"
|
||||
#include "tex.h"
|
||||
|
||||
#ifdef PORT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
/* GE_D193A=1 — per-second locomotion telemetry for one/all scripted chrs
|
||||
* (D193: "AI travels slower than N64" — the frame clock was ruled out in
|
||||
* M-80, so measure the anim-root-motion path directly). For each ticked
|
||||
* chr, once per wall-second: chrnum, actiontype, distance travelled in
|
||||
* world units over the last second (= travel speed), and the scalars that
|
||||
* feed the root-motion extraction in modelSetAnimFrame2WithChrStuff
|
||||
* (model.c:3060+): scale, anim_translation_scale, animrate, playspeed,
|
||||
* speed, endframe, plus g_GlobalTimerDelta for reference. Optionally
|
||||
* GE_D193A_CHR=<n> restricts output to that chrnum. Test-only, env-gated. */
|
||||
static int d193a_mode = -1;
|
||||
static int d193a_only = -1;
|
||||
struct D193aSlot { s16 chrnum; u8 used; f32 px, py, pz, accdist; OSTime t0; };
|
||||
static struct D193aSlot d193a_slots[48];
|
||||
static struct D193aSlot *d193aSlot(s16 n) {
|
||||
int free = -1;
|
||||
for (int i = 0; i < 48; i++) {
|
||||
if (d193a_slots[i].used && d193a_slots[i].chrnum == n) return &d193a_slots[i];
|
||||
if (free < 0 && !d193a_slots[i].used) free = i;
|
||||
}
|
||||
if (free < 0) return NULL;
|
||||
d193a_slots[free].used = 1;
|
||||
d193a_slots[free].chrnum = n;
|
||||
d193a_slots[free].accdist = 0.0f;
|
||||
d193a_slots[free].t0 = 0;
|
||||
return &d193a_slots[free];
|
||||
}
|
||||
static void d193aSample(ChrRecord *chr, Model *model) {
|
||||
if (d193a_mode < 0) {
|
||||
d193a_mode = getenv("GE_D193A") != NULL;
|
||||
const char *o = getenv("GE_D193A_CHR");
|
||||
d193a_only = o ? atoi(o) : -1;
|
||||
}
|
||||
if (!d193a_mode || model == NULL || chr->prop == NULL) return;
|
||||
if (d193a_only >= 0 && chr->chrnum != d193a_only) return;
|
||||
struct D193aSlot *s = d193aSlot(chr->chrnum);
|
||||
if (!s) return;
|
||||
f32 x = chr->prop->pos.x, y = chr->prop->pos.y, z = chr->prop->pos.z;
|
||||
OSTime now = osGetTime();
|
||||
if (s->t0 == 0) { s->t0 = now; s->px = x; s->py = y; s->pz = z; s->accdist = 0.0f; return; }
|
||||
f32 dx = x - s->px, dy = y - s->py, dz = z - s->pz;
|
||||
s->accdist += sqrtf(dx*dx + dy*dy + dz*dz);
|
||||
s->px = x; s->py = y; s->pz = z;
|
||||
if (now - s->t0 >= 1000000) {
|
||||
f32 secs = (f32)(now - s->t0) / 1e6f;
|
||||
fprintf(stderr,
|
||||
"[D193A] chr=%d act=%d speed=%.1fu/s gtd=%.2f | scale=%.4f xlscale=%.4f "
|
||||
"animrate=%.4f playspeed=%.4f mspeed=%.4f endframe=%.1f anim=%p\n",
|
||||
chr->chrnum, (int)chr->actiontype, s->accdist / secs, g_GlobalTimerDelta,
|
||||
model->scale, model->anim_translation_scale, model->animrate,
|
||||
model->playspeed, model->speed, model->endframe, (void *)model->anim);
|
||||
s->t0 = now; s->accdist = 0.0f;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VERSION_EU
|
||||
#define GROUND_SMOOTH_FACTOR 0.118799984f /* 0x3DF34D68 (PAL-scaled 0.1) */
|
||||
#define FALLSPEED_DECAY 0.8812f /* 0x3F619653 (PAL-scaled 0.9) */
|
||||
@@ -2358,6 +2416,10 @@ s32 chrTick(PropRecord *prop)
|
||||
headVisible = 1;
|
||||
tickamount = g_ClockTimer;
|
||||
|
||||
#ifdef PORT
|
||||
d193aSample(chr, model);
|
||||
#endif
|
||||
|
||||
if ((!(chr->chrflags & CHRFLAG_HIDDEN)) || (chr->chrflags & CHRFLAG_00040000))
|
||||
{
|
||||
if (D_8002C904)
|
||||
|
||||
@@ -1127,6 +1127,33 @@ f32 sub_GAME_7F06D3F4(s32 jointnum, s32 flip, ModelSkeleton *skeleton, ModelAnim
|
||||
pos->y = (f32)tmp[1];
|
||||
pos->z = (f32)tmp[2];
|
||||
|
||||
#ifdef PORT
|
||||
/* GE_D193B=1 (D193): raw root-motion decode trace. Rate-limited. Logs the
|
||||
* joint index, the mtx base channel index, the decoded s16 translation
|
||||
* triple straight out of the anim bitstream, and the derived angle. This
|
||||
* is the value that scales every scripted/AI character's travel distance
|
||||
* (model.c:3060+ multiplies it by model->scale*anim_translation_scale and
|
||||
* accumulates it into the chr root position). Compare magnitudes against a
|
||||
* clean N64 decomp build of the same anim/frame to catch a bitstream /
|
||||
* ModelSkeleton.Joints-stride / descriptor decode divergence. */
|
||||
{
|
||||
static int d193b = -1;
|
||||
static unsigned d193b_n = 0;
|
||||
if (d193b < 0) d193b = getenv("GE_D193B") != NULL;
|
||||
if (d193b && (d193b_n++ % 97) == 0) {
|
||||
s32 base = flip ? skeleton->Joints[jointnum].mtxB
|
||||
: skeleton->Joints[jointnum].mtxA;
|
||||
fprintf(stderr,
|
||||
"[D193B] joint=%d flip=%d base=%d frame=%d tmp=(%d,%d,%d) "
|
||||
"angle=%u anim=%p bd=%08x bs=%08x njoints=%d\n",
|
||||
(int)jointnum, (int)flip, (int)base, (int)frame,
|
||||
(int)tmp[0], (int)tmp[1], (int)tmp[2], (unsigned)angle,
|
||||
(void *)anim, (unsigned)anim->bitDescriptors,
|
||||
(unsigned)anim->bitStream, (int)skeleton->numjoints);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return ((f32)angle * M_TAU_F) / M_U16_MAX_VALUE_F;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user