From 18289f95f89fc02beab1e7b086bc04a3bd6c1995 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 7 Aug 2026 11:11:19 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20#345=20D0=20verdict=20=E2=80=94=20the?= =?UTF-8?q?=20stuck-tick=20fingerprint=20is=20retail's=20own=20algorithm;?= =?UTF-8?q?=20fix=20attempt=20correctly=20stopped?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Five links traced from the named decomp: the below-push never executes (OnWalkable guard — the probe printed the wrong guard pair), the from-scratch retry is retail-identical, and validate_transition's failure path manufactures every captured field including the (0,0,1) default. Stopping dead may simply BE retail. Two validations remain: the user observing their RETAIL client at a comparable slope (the cheapest decisive test there is), and — only if retail visibly slides — the find_cell_list broadphase question via the cdb toolchain. The mechanism paragraph's wrong-cause framing is retained and corrected in place, per the register's own honesty pattern. Co-Authored-By: Claude Opus 5 --- docs/ISSUES.md | 27 ++- docs/research/2026-08-08-345-pseudocode.md | 266 +++++++++++++++++++++ 2 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 docs/research/2026-08-08-345-pseudocode.md diff --git a/docs/ISSUES.md b/docs/ISSUES.md index 0730cf3f..3f2d7a06 100644 --- a/docs/ISSUES.md +++ b/docs/ISSUES.md @@ -178,7 +178,32 @@ position. Zero yield. (`oiContact=True, spStepDown=False, guardPassed=False` on every line — the morning's `collN=(0,0,1)` comes from the failure path's result-filling, not from ValidateWalkable's guard, which never passes here.) -**The fix contract's question is now precise:** what does RETAIL's +### D0 VERDICT, same day — the fingerprint IS retail's own algorithm; the fix attempt STOPPED itself + +The fix implementer's mandatory pseudocode pass traced all five links from +the named decomp (addresses in +`docs/research/2026-08-08-345-pseudocode.md`) and found the mechanism +paragraph above named the right symptom with the WRONG cause: the below-push +never executes at all (its guard is `step_down || !OnWalkable || walkable`, +and the player IS OnWalkable on the flat approach — the probe printed the +SetCollisionNormal guards, not this one); `Adjusted` retrying the whole +insert from scratch is retail-identical (`transitional_insert` @0x0050b6f0); +and `validate_transition` @0x0050aa70 on failure kills velocity, restores +the flat plane, DEFAULTS the collision normal to (0,0,1), reverts CheckPos, +and forces OK — producing every field of the captured fingerprint from +retail's own code. **Stopping dead here may simply BE retail.** + +**Two open validations before this closes either way:** +1. **The cheapest decisive test needs no debugger: the USER walks their + RETAIL client into a comparable just-too-steep hillside at ~45° and + reports slide vs dead stop.** Their expectation of sliding is currently + the only evidence against retail-faithfulness. +2. If retail visibly slides: the remaining suspect is UPSTREAM of the + walkable response — whether retail's `find_cell_list` broadphase even + queries the steep cell from this position (the pseudocode doc's open + question) — a runtime question for the cdb toolchain, not code-reading. + +**The fix contract's question (superseded by the verdict above, retained):** what does RETAIL's transitional_insert do with validate_walkable's Adjusted on a non-walkable plane — does the adjusted CheckPos feed the NEXT attempt (convergence), or does retail take a different branch entirely (slide/collision) instead of diff --git a/docs/research/2026-08-08-345-pseudocode.md b/docs/research/2026-08-08-345-pseudocode.md new file mode 100644 index 00000000..967d3d1c --- /dev/null +++ b/docs/research/2026-08-08-345-pseudocode.md @@ -0,0 +1,266 @@ +# #345 D0 — retail pseudocode pin: does `transitional_insert` slide on a too-steep OTHER-cell plane while already grounded? + +**Order:** implementation-session D0, per the mechanism contract +(`docs/research/2026-08-08-345-mechanism-contract.md`) and the +mechanism-caught finding in `docs/ISSUES.md` #345. Grep-named-first, +pseudocode-before-port, per `CLAUDE.md`'s workflow. + +**Verdict up front: retail does NOT slide here either.** Followed by hand +through four retail functions (cross-checked against an independent C# +reference for one of them), the mechanism converges to the exact same +"0% yield, repeat forever, `collN=(0,0,1)`, `slidingNormal=(0,0,0)`" +fingerprint the capture shows. This is **not** a carry-forward bug — see +"What the mechanism-session's framing got wrong" below. Per the session +contract's explicit fallback, this STOPS here without a D1/D2/D3 fix. + +## The scenario being traced + +Player is grounded, walking on a nearly-flat (~6.8°) approach terrain +triangle (the PRIMARY cell). The requested horizontal offset carries the +sphere's overlap into an ADJACENT (OTHER) terrain cell whose triangle is +too steep to be walkable: `N=(0.799,0.050,0.599)`, `N.z=0.599` just under +`FloorZ`(≈0.664). Captured fingerprint (`345-mechanism.log:279`, mover +`0x000F4243`, and `docs/ISSUES.md` #345's own summary): `dist=-0.34680` +(a different capture in the same class logged `-0.268` — same mechanism, +different exact stance), `oiContact=True`, `spStepDown=False`, +`guardPassed=False`, `outcome=Adjusted`, **identical on every one of 6 +attempts within the stuck tick**, final resolve position byte-identical +to input, `collN=(0,0,1)`, `slidingNormal=(0,0,0)`, carried contact = +the flat approach terrain, `transient=0x3` (Contact|OnWalkable). + +## 1. `OBJECTINFO::validate_walkable` (retail 0x0050d010, pc:274479-274617) + +Grep-named-first target from the contract. The "below the surface" +branch (our scenario: `dist < -EPSILON`) is: + +``` +zDist = dist / N.z +walkable = is_valid_walkable(N) // N.z >= FloorZ, ours: sp.WalkableAllowance +if (step_down != 0 || (state & ON_WALKABLE) == 0 || walkable != 0) { + set_contact_plane(plane, cellId) + if (step_down) { ...interpolation reject... } + AddOffsetToCheckPos(0, 0, -zDist) // THE PUSH — pc:274604-274607 +} +if ((state & CONTACT) == 0 && step_down == 0) { + set_collision_normal(plane) + collided_with_environment = 1 +} +return ADJUSTED_TS +``` + +Cross-checked against `references/ACE/Source/ACE.Server/Physics/ObjectInfo.cs:142-170` +(`ObjectInfo.ValidateWalkable`, independently-authored C# port of the +same algorithm) — **identical structure**, same three-way OR gate before +the push. + +**The push (`AddOffsetToCheckPos`) is gated behind +`step_down || !OnWalkable || walkable`.** In our scenario: `step_down` +is false (confirmed by the trace's `spStepDown=False`), `walkable` is +false (0.599 < FloorZ), so the push fires **only if `OnWalkable` is +false**. Our C# (`TransitionTypes.cs:3746-3769`) ports this gate +verbatim: `if (sp.StepDown || !oi.OnWalkable || walkable)`. + +**Is `OnWalkable` true here?** Yes — confirmed by +`PhysicsEngine.cs:2026-2047`: at the start of every resolve, when the +body is in contact with a valid plane and not moving away from it +(`check_contact`'s success branch, ported faithfully per the #32 commit +history), `if (body.OnWalkable) transition.ObjectInfo.State |= OnWalkable;`. +The player IS resting on the flat approach terrain — `body.OnWalkable` +is true — so `oi.OnWalkable` is true for this entire resolve. + +**Conclusion: the push never fires. `ValidateWalkable` returns +`ADJUSTED_TS` with ZERO state mutation** — no `SetContactPlane`, no +`AddOffsetToCheckPos`, and (since `!oi.Contact` is false per the trace's +`oiContact=True`) no `SetCollisionNormal` either. This is retail's own +intentional design: a sphere already stably grounded elsewhere does not +get shoved around by an incidental graze against a DIFFERENT, non-walkable +patch. **There is no "adjustment" to carry forward — there never was one +to begin with.** The mechanism-session's framing ("push-up... the +adjustment does not carry forward between attempts") named the right +symptom (identical `dist` every attempt) but the wrong cause (it isn't +that a real push gets discarded; it's that the push never executes at +all, precisely as retail specifies for a grounded-elsewhere mover). + +## 2. `CTransition::transitional_insert` (retail 0x0050b6f0, pc:273137-273364) + +``` +edi = INVALID_TS +for (attempt = 0; attempt < numAttempts; attempt++) { + edi = insert_into_cell(check_cell, numAttempts) + switch (edi) { + case OK_TS: + edi = check_other_cells(check_cell) // overwrites edi + if (edi != OK_TS) neg_poly_hit = 0 + if (edi == COLLIDED_TS) return COLLIDED_TS + break // falls to "if edi==OK_TS" below + case COLLIDED_TS: + neg_poly_hit = 0 + return edi + case ADJUSTED_TS: + neg_poly_hit = 0 + break // falls straight to loop-bottom, no retry-with-state + case SLID_TS: + contact_plane_valid = 0; contact_plane_is_water = 0 + neg_poly_hit = 0 + break + } + if (edi == OK_TS) { + ...sphere_path.collide handling (Phase 3)... + ...neg_poly_hit dispatch (step_up / step_up_slide / slide_sphere)... + } + // loop-bottom: unconditional retry up to numAttempts, no early exit besides + // the explicit returns above +} +return edi +``` + +Our C# (`TransitionTypes.cs:1991-2037` for the switch, +`2052-2065` for the `check_other_cells` dispatch) matches this +line-for-line: `InsertIntoCell` result dispatches through the same +Collided-returns/Adjusted-clears-neg-poly-continues/Slid-clears-contact- +continues shape; `OK_TS` alone proceeds to `RunCheckOtherCellsAndAdvance` +(our name for `check_other_cells`), whose non-OK result also just +`continue`s the outer loop with **no special-cased state restoration** — +identical to retail's `break` that skips the big Phase-3 block and falls +to the unconditional loop-bottom retry. + +**Neither retail nor our port does anything to "feed the adjusted +CheckPos forward" on an `ADJUSTED_TS` from `check_other_cells` — both +simply retry the WHOLE `insert_into_cell` from scratch.** Since +`ValidateWalkable` made zero mutation (§1), retrying from scratch +necessarily reproduces the identical primary-insert-OK, +other-cell-Adjusted-with-identical-`dist` sequence every attempt. This +is exactly the observed fingerprint, and it is retail-faithful. + +## 3. `CTransition::check_other_cells` (retail 0x0050ae50, pc:272717-272798) + +Iterates the sphere's overlapping OTHER cells (`find_cell_list`), calling +each cell's virtual `find_collisions`. Its switch: `COLLIDED_TS` and +`ADJUSTED_TS` (cases 2 and 3) **both `return result` immediately** — no +further cells are tried, no retry loop of its own. `SLID_TS` (case 4) +clears the contact plane fields then also returns immediately. Only +`OK_TS` continues to the next cell. Our C# `CheckOtherCells` / +`ApplyOtherCellResult` (`TransitionTypes.cs:2952-3030`) halts the same +way. No divergence found here. + +## 4. `CTransition::validate_transition` (retail 0x0050aa70, pc:272547-272689) + +Called as `validate_transition(this, transitional_insert(this, 3), &out)` +directly from `find_transitional_position` (retail 0x0050bdf0, +pc:273743 — the ordinary per-substep walking driver, confirmed calling +exactly `transitional_insert(this, 3)` then `validate_transition`, +matching our `TransitionTypes.cs:1611/1621` +`TransitionalInsert(3, engine)` → `ValidateTransition(result)` pairing +byte-for-byte). On a non-OK, non-INVALID result (COLLIDED/ADJUSTED/SLID +— **all three, treated identically**): + +``` +if (last_known_contact_plane_valid) { + kill_velocity() + if (radius + EPSILON > |dot(N_lkcp, curr_center) + d_lkcp|) // still within + set_contact_plane(last_known_contact_plane) // reach of LKCP? +} +if (!collision_normal_valid) + set_collision_normal(UP) // the (0,0,1) DEFAULT FILL +set_check_pos(curr_pos, curr_cell) // DISCARD — revert to pre-step position +result = OK_TS // FORCE OK — the whole substep nets zero +... +if (collision_normal_valid) + set_sliding_normal(collision_normal) // sliding_normal = f(UP) below +``` + +Our C# `ValidateTransition` (`TransitionTypes.cs:6194-6226`) ports this +exactly, including the `LastKnownContactPlaneValid` proximity gate +(`TransitionTypes.cs:6203-6219`), the `!CollisionNormalValid` UP default +(`6221-6222`, the literal source of the trace's `collN=(0,0,1)` — +confirming the mechanism-session's own annotation that this normal +"comes from the failure path's result-filling, not from +`ValidateWalkable`'s guard"), the `SetCheckPos` revert + forced `OK_TS` +(`6224-6225`), and the `SetSlidingNormal(CollisionNormal)` call +(`6229-6230`). + +**Because the player is still resting on the flat approach terrain, +`curr_center` is (by construction) essentially ON that plane, so the +LKCP-proximity check always passes — the flat terrain gets restored as +the CURRENT contact plane on every failed substep.** That is why the +capture shows `carried contact = the flat approach terrain`, not the +steep face — the steep face never gets registered as a contact at all +(§1), and this LKCP restore keeps re-confirming `OnWalkable = true` +(`ContactPlane.Normal.Z(0.993) >= FloorZ`) at the tail of `ValidateTransition` +(`TransitionTypes.cs:6252-6255`) — which is exactly the `OnWalkable` +seed §1 needs to keep suppressing the push on the NEXT resolve. **This +is a self-sustaining, retail-faithful attractor**: stay resting on flat +ground behind you → steep OTHER-cell touch is silently ignored → +contact plane keeps re-anchoring to the flat ground → `OnWalkable` stays +true → the steep touch keeps being silently ignored. There is no state +transition inside this mechanism that would break the cycle. + +## 5. `COLLISIONINFO::set_sliding_normal` (the "#331 absorb") + +`TransitionTypes.cs:553-559` projects the incoming normal to XY only +and re-normalizes: + +```csharp +SlidingNormal = new Vector3(normal.X, normal.Y, 0f); +if (SlidingNormal.LengthSquared() > EpsilonSq) + SlidingNormal = Vector3.Normalize(SlidingNormal); +``` + +Fed the §4 UP default `(0,0,1)`, this produces `SlidingNormal=(0,0,0)` +— **exactly the captured `slidingNormal=(0,0,0)`.** Per the trap +inventory (`docs/research/2026-08-08-345-mechanism-contract.md` + +`CLAUDE.md` "Current state"), this XY-projection is the retail-faithful +#331 absorb and is explicitly off-limits to touch. It is not the cause +here — it is a correct, downstream consequence of the §4 UP default, +which is itself a correct, downstream consequence of §1's guard never +firing. + +## What the mechanism-session's framing got wrong + +The probe (`ACDREAM_DUMP_TRANSIT_FAIL`) correctly found WHERE the +identical-`dist` loop lives (`ValidateWalkable`'s below-branch, +`TransitionalInsert`'s retry). It inferred WHY from the symptom's shape +("push-up... doesn't carry forward") without visibility into `oi.OnWalkable` +or the push guard itself — the probe's trace only carries `oiContact`/ +`spStepDown` (the *second*, `SetCollisionNormal`, guard), not the *first* +(`AddOffsetToCheckPos`) guard's inputs. Reading the guard from source +(`sp.StepDown || !oi.OnWalkable || walkable`, all three legs resolvable +statically for this scenario) shows the push is **never attempted**, so +there is nothing to "carry forward" in the first place. + +## Conclusion + +Every function in the chain — `ValidateWalkable`, `TransitionalInsert`, +`CheckOtherCells`, `ValidateTransition`, `SetSlidingNormal` — is a +faithful, citable port, and hand-tracing them against this exact +scenario reproduces every byte of the captured fingerprint (`collN=(0,0,1)`, +`slidingNormal=(0,0,0)`, identical `dist` per attempt, carried contact = +approach terrain, byte-identical position in/out). **Retail's own +algorithm, run by hand against this geometry, does not slide — it +converges to the same zero-yield stop.** Per the mechanism-session +contract's explicit fallback ("If retail turns out NOT to slide here +either, STOP and report — the user's expectation would then be the +divergence, a different decision"), this session stops here. No +`ValidateWalkable`/`TransitionalInsert`/`ValidateTransition` change is +made; #331, #32, and AD-65 are untouched, matching the trap inventory. + +## Open question for whoever picks this up next + +The one link in this chain NOT fully verified against retail is **cell +membership**: does retail's `CObjCell::find_cell_list` (feeding +`check_other_cells`'s cell array) actually include this neighboring +too-steep OTHER cell from the player's exact resting position, or does +our `CellTransit`/other-cells construction query a cell retail's +narrower geometry test would not have reached at all? That is a +genuinely different question from anything traced above (a broadphase/ +cell-array question, not a walkable-response question), and it is the +one place this D0 pass had to reason from citation rather than from a +direct retail-vs-acdream A/B. The toolchain's own guidance applies +here: this is exactly the "what does retail actually DO at runtime" +class of question the cdb toolchain +(`memory/reference_retail_debugger.md`) exists for — attach to a live +retail client at the identical Rithwic steep face and confirm whether +retail's player is ALSO immovable at this exact stance, or whether it +is already sliding by the time the sphere reaches this position (which +would point at the cell-array question above, not at anything in this +document).