docs+cleanup: env-var regression + Run↔Walk cycle bug filed; re-throttle diags

End-of-session cleanup of the 2026-05-03 remote-motion debug session.

Documentation:

- CLAUDE.md: add ⚠️ DO-NOT-ENABLE warning for ACDREAM_INTERP_MANAGER=1
  in the diagnostic env-vars list. Add an "Outbound motion wire format"
  section documenting acdream's WalkForward+HoldKey.Run encoding (which
  ACE auto-upgrades to RunForward on relay) so future sessions don't
  re-derive it.

- docs/ISSUES.md: file two new issues:
  * #39 — Run↔Walk cycle transition not visible on observed
    retail-driven player remotes when watched from acdream. Root cause
    located: ApplyServerControlledVelocityCycle is gated by
    IsPlayerGuid, excluding the exact case where ACE doesn't broadcast
    a UM (shift toggle while direction key held). Fix sketch ~10
    lines, separate commit. Cross-references the four-agent
    investigation prompt.
  * #40 — ACDREAM_INTERP_MANAGER=1 env-var path regressed. Documents
    why (e94e791 conflated MoveOrTeleport with update_object), the
    visible symptoms (staircase Z, position blips), and why
    Commit B (039149a)'s ResolveWithTransition port was insufficient
    (env-var path also clears body.Velocity → no horizontal Euler
    motion → sweep input is queue catch-up only, which stair-steps).
    Fix path = separate L.3 follow-up to re-integrate PositionManager
    additively on top of the legacy chain.

Code:

- GameWindow.cs:6042: prepend a ⚠️ REGRESSED warning block at the top
  of the env-var per-frame branch so anyone reading the code is
  immediately aware not to enable it. Cross-references ISSUES.md #40.

- AnimationSequencer.cs: re-throttle [SCFAST]/[SCFULL] diagnostics to
  0.5s per instance (rolled back from A.1's unthrottled experiment).
  Already served its purpose; throttled is enough for steady-state
  diagnostics. Restore _lastSetCycleDiagTime field.

No behavior change for any current launch (env-var unset = legacy
path unchanged). Build green; baseline test failures (8) unchanged
from prior commit, none introduced by this session.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-05-04 10:10:10 +02:00
parent 039149a9d0
commit a3f53c2644
4 changed files with 238 additions and 24 deletions

View file

@ -6041,6 +6041,28 @@ public sealed class GameWindow : IDisposable
{
if (System.Environment.GetEnvironmentVariable("ACDREAM_INTERP_MANAGER") == "1")
{
// ⚠️ REGRESSED 2026-05-03 — DO NOT ENABLE — see docs/ISSUES.md #40 ⚠️
//
// Introduced by e94e791 (L.3.1+L.3.2 Task 3) intending to
// mirror retail CPhysicsObj::MoveOrTeleport (network-packet
// entry point — minimal work). Wrong retail function for the
// per-frame tick — the actual per-frame chain is retail's
// update_object (FUN_00515020), which the LEGACY path below
// correctly mirrors (apply_current_movement →
// UpdatePhysicsInternal → ResolveWithTransition collision
// sweep). This env-var path strips the collision sweep AND
// clears body.Velocity, leaving only PositionManager queue
// catch-up — which stair-steps with the 1 Hz UP cadence on
// slopes and produces visible position blips on flat ground.
//
// Commit B (039149a, 2026-05-03) ported ResolveWithTransition
// here but symptom persists because body.Velocity=0 means
// pre/postIntegrate sweep input is just the queue catch-up,
// which itself snaps in steps. Fix requires re-integrating
// PositionManager as ADDITIVE adjust_offset on top of the
// legacy chain — separate L.3 follow-up phase.
//
// Until that lands, stay on the legacy path (env-var unset).
// ── NEW PATH: retail-faithful per-frame remote tick ──
// (L.3.1+L.3.2 Task 3/follow-up — ACDREAM_INTERP_MANAGER=1 gates this path)
//

View file

@ -283,9 +283,12 @@ public sealed class AnimationSequencer
private const double RateEpsilon = 1e-6;
// ── Diagnostics (Commit A 2026-05-03) ───────────────────────────────────
// Removed throttle in A.1 (2026-05-03) — every SCFAST/SCFULL call logs
// unthrottled (still gated on ACDREAM_REMOTE_VEL_DIAG=1) so we can read
// exact call rate and Run→Ready transitions one tick at a time.
// Throttle clock for the [SCFAST] / [SCFULL] / [SCNULLFALLBACK] log lines
// emitted from SetCycle. Gated on env var ACDREAM_REMOTE_VEL_DIAG=1; reads
// the env var inline rather than caching so a launch can be re-toggled
// without restarting. 0.5s per sequencer instance keeps logs readable
// while still capturing meaningful state changes.
private double _lastSetCycleDiagTime;
// ── Constructor ──────────────────────────────────────────────────────────
@ -413,17 +416,20 @@ public sealed class AnimationSequencer
}
// D3 (Commit A 2026-05-03): SCFAST — proves whether the fast-path
// is firing instead of the full rebuild.
// A.1 (2026-05-03): unthrottled — we need actual call rate, not
// 0.5s-bucketed sample. Keeps cost low (just a Console.WriteLine
// per SetCycle call, all gated on env var).
// is firing instead of the full rebuild. Throttled to 0.5s per
// instance (re-throttled after A.1 unthrottled experiment).
if (System.Environment.GetEnvironmentVariable("ACDREAM_REMOTE_VEL_DIAG") == "1")
{
System.Console.WriteLine(
$"[SCFAST] motion=0x{motion:X8} speedMod={speedMod:F3} "
+ $"oldSpeedMod={CurrentSpeedMod:F3} "
+ $"qCount={_queue.Count} "
+ $"currNodeIsCyclic={(_currNode == _firstCyclic)}");
double nowSec = (System.DateTime.UtcNow - System.DateTime.UnixEpoch).TotalSeconds;
if (nowSec - _lastSetCycleDiagTime > 0.5)
{
System.Console.WriteLine(
$"[SCFAST] motion=0x{motion:X8} speedMod={speedMod:F3} "
+ $"oldSpeedMod={CurrentSpeedMod:F3} "
+ $"qCount={_queue.Count} "
+ $"currNodeIsCyclic={(_currNode == _firstCyclic)}");
_lastSetCycleDiagTime = nowSec;
}
}
return;
}
@ -546,20 +552,23 @@ public sealed class AnimationSequencer
}
// D3 (Commit A 2026-05-03): SCFULL — counterpart to SCFAST. Fires on
// the full-rebuild SetCycle path.
// A.1 (2026-05-03): unthrottled — see SCFAST comment. We also print
// the previous CurrentMotion so the log directly shows the cycle
// transition (e.g. "Run → Ready" indicates the visible cycle just
// got reset back to Ready, mid-Run).
// the full-rebuild SetCycle path. Throttled to 0.5s per instance.
// Logs prev CurrentMotion so the line shows the transition directly
// (e.g. "Run → Ready" = cycle just got reset).
if (System.Environment.GetEnvironmentVariable("ACDREAM_REMOTE_VEL_DIAG") == "1")
{
System.Console.WriteLine(
$"[SCFULL] prev=0x{CurrentMotion:X8} -> motion=0x{motion:X8} adjustedMotion=0x{adjustedMotion:X8} "
+ $"speedMod={speedMod:F3} "
+ $"qCount={_queue.Count} "
+ $"firstNewNull={(firstNew is null)} "
+ $"currNodeIsCyclic={(_currNode == _firstCyclic)} "
+ $"firstCyclicNull={(_firstCyclic is null)}");
double nowSec = (System.DateTime.UtcNow - System.DateTime.UnixEpoch).TotalSeconds;
if (nowSec - _lastSetCycleDiagTime > 0.5)
{
System.Console.WriteLine(
$"[SCFULL] prev=0x{CurrentMotion:X8} -> motion=0x{motion:X8} adjustedMotion=0x{adjustedMotion:X8} "
+ $"speedMod={speedMod:F3} "
+ $"qCount={_queue.Count} "
+ $"firstNewNull={(firstNew is null)} "
+ $"currNodeIsCyclic={(_currNode == _firstCyclic)} "
+ $"firstCyclicNull={(_firstCyclic is null)}");
_lastSetCycleDiagTime = nowSec;
}
}
CurrentStyle = style;