From 4cad626ff55ad192f19c69811312c0f7c7185ad4 Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 4 Jul 2026 22:31:00 +0200 Subject: [PATCH] chore(#170): strip the temp probes, close the issue (user visual gate PASSED) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gate result: user side-by-side vs retail — "looks good, as close to retail now as I can see". Telemetry from the gate session (launch-170-gate2.log): BeginMoveForward ~1:1 with MoveToObject arms for every chasing creature (pre-fix capture was 16:1), ZERO "SERVERVEL skips UseTime while armed" occurrences, pending_motions depth 1 at last sample. Stripped per the #170 close-out plan: s_mvtoDiag + all [mvto] prints (MoveToManager), s_drainDiag + [drain]/[drainq] (MotionInterpreter), the [npc-tick] branch prints and the "UM actions" inbound-action dump (GameWindow). The durable ACDREAM_DUMP_MOTION family stays. The RemoteChaseEndToEndHarnessTests + RemoteChaseDrainBisectTests conformance suites stay as the permanent regression net for this pipeline. ISSUES: #170 -> DONE + Recently-closed entry (fix SHAs 427332ac, d2ccc80e, 1051fc83). Memory topic + index flipped to CLOSED. Co-Authored-By: Claude Fable 5 --- docs/ISSUES.md | 29 +++++++++++++++++-- src/AcDream.App/Rendering/GameWindow.cs | 29 ------------------- .../Physics/Motion/MoveToManager.cs | 28 ------------------ src/AcDream.Core/Physics/MotionInterpreter.cs | 26 ----------------- 4 files changed, 27 insertions(+), 85 deletions(-) diff --git a/docs/ISSUES.md b/docs/ISSUES.md index 361dd63f..353a5b1c 100644 --- a/docs/ISSUES.md +++ b/docs/ISSUES.md @@ -48,8 +48,13 @@ Copy this block when adding a new issue: ## #170 — Remote creature chase+attack renders wrong vs retail (glide, over-frequency, uniform attack anims) -**Status:** OPEN — **residual fix landed 2026-07-04 ("sustain the run" — SERVERVEL -starvation); AWAITING VISUAL GATE.** Fix #1 (`427332ac`): the per-frame +**Status:** DONE (2026-07-04) — **user visual gate PASSED** ("looks good, as close +to retail now as I can see"). Fixes: `427332ac` (per-frame re-dispatch flood) + +`d2ccc80e` (velocity refresh) + `1051fc83` (armed moveto always ticks UseTime — the +SERVERVEL starvation) + probe strip. Gate telemetry (launch-170-gate2.log): run +installs ≈ 1:1 with arms for every chasing creature (was 16:1), zero +armed-moveto UseTime skips, queue depth 1. (Move to Recently closed on next +ISSUES tidy.) History below. Fix #1 (`427332ac`): the per-frame `apply_current_movement` re-dispatch flooded `pending_motions` to ~1.3M → deleted; flood 1.3M→~1, "stuck attack" gone (user-confirmed), run installs 1→10. Fix #2 (this session): **the "slow Ready drain" framing was WRONG** — a full-stack offline harness @@ -5967,6 +5972,26 @@ outdoors at the angle that previously erased it. # Recently closed +## #170 — Remote creature chase+attack renders wrong vs retail (glide, run not sustained) + +**Status:** DONE (2026-07-04, user visual gate passed — "as close to retail now as +I can see"). Three-fix arc: `427332ac` deleted the per-frame +`apply_current_movement` re-dispatch that flooded `pending_motions` to ~1.3M +(chase turn permanently blocked → slide); `d2ccc80e` refreshed remote body +velocity from `get_state_velocity`; `1051fc83` fixed the residual — the +SERVERVEL per-tick branch skipped `MoveToManager.UseTime` for any UP-receiving +NPC, starving the armed moveto for the whole server-side chase (funnel 16 arms → +1 run install; retail runs `MovementManager::UseTime` unconditionally, +`UpdateObjectInternal` 0x005156b0 @0x00515998) — an armed moveto now always takes +the MOVETO leg. The intermediate "Ready drain too slow" hypothesis was DISPROVEN +by the full-stack offline harness (`RemoteChaseEndToEndHarnessTests` + +`RemoteChaseDrainBisectTests`, kept as conformance). Register: TS-41 narrowed, +TS-42 added (one-frame drain-order divergence, R6). Gate telemetry +(launch-170-gate2.log): installs ≈ arms for every creature, zero armed-moveto +UseTime skips, queue depth 1. Probes stripped in the closing commit. The full +investigation record stays in the OPEN-section body (moves here on next tidy) + +`docs/research/2026-07-04-170-creature-run-handoff.md`. + ## #163 — Strip the R4-V5 stall-investigation diagnostics **Status:** DONE (2026-07-03, `5ebe2be3`) — removed `[autowalk-gate]` (+ diff --git a/src/AcDream.App/Rendering/GameWindow.cs b/src/AcDream.App/Rendering/GameWindow.cs index 5862c1d8..5e81c121 100644 --- a/src/AcDream.App/Rendering/GameWindow.cs +++ b/src/AcDream.App/Rendering/GameWindow.cs @@ -4977,29 +4977,6 @@ public sealed class GameWindow : IDisposable Speed: item.Speed)); } ims.Actions = actionList; - - // #170 capture aid (ACDREAM_DUMP_MOTION): dump the - // REMOTE inbound action list WITH stamps — the - // existing UM line only shows ForwardCommand, and the - // [CMD_LIST] dump is local-player only. This is what - // answers "do the attack stamps advance (variety) or - // repeat (uniform)?". Strip once #170 is understood. - if (Environment.GetEnvironmentVariable("ACDREAM_DUMP_MOTION") == "1") - { - var sb = new System.Text.StringBuilder(); - sb.Append(System.FormattableString.Invariant( - $"UM ↳ actions guid=0x{update.Guid:X8} mt=0x{update.MotionState.MovementType:X2} fwd=0x{ims.ForwardCommand:X8} [")); - for (int ai = 0; ai < actionList.Count; ai++) - { - var a = actionList[ai]; - var rt = AcDream.Core.Physics.AnimationCommandRouter.Classify(a.Command); - if (ai > 0) sb.Append(", "); - sb.Append(System.FormattableString.Invariant( - $"0x{a.Command:X8}({rt}) stamp={a.Stamp} auto={a.Autonomous} spd={a.Speed:F2}")); - } - sb.Append(']'); - Console.WriteLine(sb.ToString()); - } } // R2-Q5/R3-W4: funnel dispatches go STRAIGHT into the @@ -9986,9 +9963,6 @@ public sealed class GameWindow : IDisposable { MovementTypeState: not AcDream.Core.Physics.MovementType.Invalid }; if (!IsPlayerGuid(serverGuid) && rm.HasServerVelocity && !moveToArmed) { - if (Environment.GetEnvironmentVariable("ACDREAM_MVTO_DIAG") == "1") - Console.WriteLine(System.FormattableString.Invariant( - $"[npc-tick] guid={serverGuid:X8} branch=SERVERVEL (skips UseTime) mtState={rm.MoveTo?.MovementTypeState}")); double velocityAge = nowSec - rm.LastServerPosTime; if (velocityAge > ServerControlledVelocityStaleSeconds) { @@ -10015,9 +9989,6 @@ public sealed class GameWindow : IDisposable // per-node locomotion (turn / RunForward) through the // sink. That per-node dispatch is the only motion the // per-tick update should issue for a remote. - if (Environment.GetEnvironmentVariable("ACDREAM_MVTO_DIAG") == "1") - Console.WriteLine(System.FormattableString.Invariant( - $"[npc-tick] guid={serverGuid:X8} branch=MOVETO (UseTime runs) mtState={rm.MoveTo?.MovementTypeState}")); TickRemoteMoveTo(rm); // #170 ROOT FIX (2026-07-04): the per-frame diff --git a/src/AcDream.Core/Physics/Motion/MoveToManager.cs b/src/AcDream.Core/Physics/Motion/MoveToManager.cs index 37e3cce8..ac943c80 100644 --- a/src/AcDream.Core/Physics/Motion/MoveToManager.cs +++ b/src/AcDream.Core/Physics/Motion/MoveToManager.cs @@ -738,12 +738,6 @@ public sealed class MoveToManager /// (/ = dist, /// both times = now). /// - // #170 temp diag (ACDREAM_MVTO_DIAG): trace the MoveTo dispatch/re-drive/cancel - // events to compare acdream's run-cycle install cadence against a live retail - // cdb count. Strip once #170 is understood. - private static readonly bool s_mvtoDiag = - System.Environment.GetEnvironmentVariable("ACDREAM_MVTO_DIAG") == "1"; - public void BeginMoveForward() { if (!HasPhysicsObj) @@ -762,10 +756,6 @@ public sealed class MoveToManager Params.GetCommand(dist, heading, out uint cmd, out HoldKey holdKey, out bool movingAway); - if (s_mvtoDiag) - System.Console.WriteLine(System.FormattableString.Invariant( - $"[mvto] BeginMoveForward dist={dist:F2} cmd=0x{cmd:X8} hold={holdKey} movingAway={movingAway}")); - if (cmd == 0) { RemovePendingActionsHead(); @@ -826,10 +816,6 @@ public sealed class MoveToManager return; } - if (s_mvtoDiag) - System.Console.WriteLine(System.FormattableString.Invariant( - $"[mvto] BeginTurnToHeading motionsPending={_interp.MotionsPending()} curCmd=0x{CurrentCommand:X8}")); - if (_interp.MotionsPending()) { return; @@ -966,10 +952,6 @@ public sealed class MoveToManager /// public void UseTime() { - if (s_mvtoDiag && (MovementTypeState != MovementType.Invalid || _pendingActions.First is not null)) - System.Console.WriteLine(System.FormattableString.Invariant( - $"[mvto] UseTime enter contact={_contact()} pending={_pendingActions.Count} mtState={MovementTypeState} init={Initialized} hasPhys={HasPhysicsObj}")); - if (!HasPhysicsObj || !_contact()) return; if (_pendingActions.First is null) return; @@ -978,9 +960,6 @@ public sealed class MoveToManager if (!objectMoveGate) return; MovementType type = _pendingActions.First.Value.Type; - if (s_mvtoDiag) - System.Console.WriteLine(System.FormattableString.Invariant( - $"[mvto] UseTime dispatch node={type} mtState={MovementTypeState}")); if (type == MovementType.MoveToPosition) { HandleMoveToPosition(); @@ -1249,10 +1228,6 @@ public sealed class MoveToManager /// public void HandleUpdateTarget(TargetInfo info) { - if (s_mvtoDiag) - System.Console.WriteLine(System.FormattableString.Invariant( - $"[mvto] HandleUpdateTarget objId=0x{info.ObjectId:X8} myTgt=0x{TopLevelObjectId:X8} match={(TopLevelObjectId == info.ObjectId)} init={Initialized} mtState={MovementTypeState} status={info.Status}")); - if (!HasPhysicsObj) { CancelMoveTo(WeenieError.NoPhysicsObject); @@ -1485,9 +1460,6 @@ public sealed class MoveToManager /// public void CancelMoveTo(WeenieError error) { - if (s_mvtoDiag && MovementTypeState != MovementType.Invalid) - System.Console.WriteLine($"[mvto] CancelMoveTo (real) wasType={MovementTypeState} err={error}"); - _ = error; // retail: never read in the body (decomp §7c) — kept for parity/logging. if (MovementTypeState == MovementType.Invalid) return; diff --git a/src/AcDream.Core/Physics/MotionInterpreter.cs b/src/AcDream.Core/Physics/MotionInterpreter.cs index e30a7dfa..9d42e51c 100644 --- a/src/AcDream.Core/Physics/MotionInterpreter.cs +++ b/src/AcDream.Core/Physics/MotionInterpreter.cs @@ -2286,34 +2286,9 @@ public sealed class MotionInterpreter : IMotionDoneSink /// Retail arg2MotionNode.context_id. /// Retail arg3MotionNode.motion. /// Retail arg4MotionNode.jump_error_code. - // #170 temp drain diag (ACDREAM_MVTO_DIAG): aggregate add_to_queue vs - // MotionDone counts + this interp's pending depth — the apples-to-apples of - // the retail cdb drain trace (retail: add==done). Strip after #170. - private static readonly bool s_drainDiag = - System.Environment.GetEnvironmentVariable("ACDREAM_MVTO_DIAG") == "1"; - private static int s_addCount; - private static int s_doneCount; - public void AddToQueue(uint contextId, uint motion, uint jumpErrorCode) { _pendingMotions.AddLast(new MotionNode(contextId, motion, jumpErrorCode)); - if (s_drainDiag) - { - s_addCount++; - // Dump this interp's queue CONTENTS whenever a backlog is present - // (depth >= 2 = something isn't draining) so we can see WHICH motion - // lingers and keeps MotionsPending() true (blocking the chase turn). - if (_pendingMotions.Count >= 2) - { - var sb = new System.Text.StringBuilder(); - foreach (var n in _pendingMotions) { sb.Append("0x"); sb.Append(n.Motion.ToString("X8")); sb.Append(' '); } - System.Console.WriteLine(System.FormattableString.Invariant( - $"[drainq] depth={_pendingMotions.Count} lag={s_addCount - s_doneCount} q=[{sb}]")); - } - else if (s_addCount % 50 == 0) - System.Console.WriteLine(System.FormattableString.Invariant( - $"[drain] add={s_addCount} done={s_doneCount} lag={s_addCount - s_doneCount} depth={_pendingMotions.Count}")); - } } /// @@ -2363,7 +2338,6 @@ public sealed class MotionInterpreter : IMotionDoneSink if (head1 is not null) { _pendingMotions.RemoveFirst(); - if (s_drainDiag) s_doneCount++; } }