feat(R1-P0/P1): CSequence research base + verbatim AnimSequenceNode

P0 — research + pins: full CSequence-family verbatim extraction (1756
lines, per-function raw pseudo-C + cleaned flow, decomp line anchors),
ACE cross-reference (9 ranked divergences; headline: retail frame_number
is x87 long double — ACE's float is the worst case, our double the best
available; ACE's frame-boundary epsilon is an ACE fabrication, NOT
retail), current-sequencer map, and the R1 gap map (20 gaps, 13 keeps,
P0-P6 port order). Pinned the one decomp ambiguity (leftover-time carry
after advance_to_next_animation — ACE reading adopted; cdb confirmation
protocol recorded, non-blocking).

P1 — AnimSequenceNode verbatim (gap G1/G2/G16/G18):
- direction-aware BARE-INT boundary pair (get_starting_frame 0x00525c80 /
  get_ending_frame 0x00525cb0): reverse starts at high+1, ends at low —
  NO epsilon;
- multiply_framerate (0x00525be0) swaps low/high on negative factor;
- set_animation_id (0x00525d60) retail clamp order (high<0 -> num-1;
  low>=num -> num-1; high>=num -> num-1; low>high -> high=low);
- ctors with retail defaults (30f/-1/-1; AnimData copy + clamp);
- get_pos_frame null out-of-range (retail; ACE returns identity),
  floor double overload; get_part_frame same discipline;
- NO per-node IsLooping/Velocity/Omega — loop membership is list
  structure, physics accumulators live on the sequence (G16).

22 conformance tests (clamp table, boundary mirror table, swap
round-trip, bounds/floor semantics).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-07-02 19:45:56 +02:00
parent cae56afc82
commit 1371c2a14c
7 changed files with 3363 additions and 0 deletions

View file

@ -0,0 +1,55 @@
# R1-P0 — pseudocode pins and ambiguity resolutions
The verbatim extraction lives in `r1-csequence-decomp.md` (1,756 lines, per-
function raw pseudo-C + cleaned translation, line anchors into
`docs/research/named-retail/acclient_2013_pseudo_c.txt`). This note records
the corrections and pins the R1 port codes against, per the gap map
(`r1-gap-map.md`).
## Corrections to the extraction (verified against raw decomp + ACE)
1. **§21 `update_internal` cleaned flow is garbled in two places.** The
authoritative skeleton is ACE `Sequence.cs:351-443` (verified verbatim,
matches the raw decomp branch layout at 0x005255d0-0x005259ca):
overshoot check → clamp `frame_number` to `get_high_frame()` (fwd) /
`get_low_frame()` (rev) + compute `frameTimeElapsed` leftover +
`animDone = true` → per-frame crossing loop → `if (!animDone) return`
AnimDone gate (`anim_list.head != first_cyclic`) →
`advance_to_next_animation` → carry leftover → loop.
2. **Hook direction constants**: forward crossings pass +1
(0x0052578c, counter `++` after), reverse pass 1 (0x0052590c, counter
`--` after). Retail encoding == ACE/DatReaderWriter `AnimationHookDir`
(Backward=1 / Both=0 / Forward=1) — no remap.
## PINNED ambiguity — leftover-time carry after node advance
Raw decomp at 0x0052598a-0x0052598d APPEARS to zero the elapsed argument
after `advance_to_next_animation` before looping; ACE carries the leftover
(`timeElapsed = frameTimeElapsed`, Sequence.cs:436-442).
**PIN: the ACE reading (carry the leftover).** Rationale: (a) Binary Ninja
routinely loses x87 stack-slot reassignments (the same artifact class as the
garbled setcc returns in `is_newer`); (b) zeroing would make a lag spike
unable to fast-forward through multiple queued nodes in one tick, visibly
freezing links under hitches — behavior nobody has ever reported on retail;
(c) the loop structure (`while(true)` with the leftover recomputed per
node) only makes sense with a carry.
**Confirmation pending (not blocking):** cdb breakpoints on
`acclient!CSequence::update` + `acclient!CSequence::advance_to_next_animation`
with hit counters (pattern `tools/cdb/l2g-observer.cdb`) under an induced
stall — an advance/update ratio > 1 in a single update proves the carry.
Fold into the next live retail session; if it DISPROVES the carry, the fix
is one line in `update_internal` + rerun of the P4 conformance suite.
## P0 addenda for later stages
- The same cdb session should also capture `append_animation` /
`remove_cyclic_anims` argument logs (P2/P5 goldens) — one session serves
all of R1.
- `frame_number` is x87 `long double` (acclient.h:30747); C# `double` is the
closest available → divergence-register row lands with the P2 commit
(G15).
- ACE's `PhysicsGlobals.EPSILON` subtraction in
`get_starting/get_ending_frame` is an ACE fabrication (compensating for
ACE's `float FrameNumber`) — retail returns bare ints. Do NOT copy (G1).