chore(#170): strip the temp probes, close the issue (user visual gate PASSED)
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 SHAs427332ac,d2ccc80e,1051fc83). Memory topic + index flipped to CLOSED. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
1051fc83c6
commit
4cad626ff5
4 changed files with 27 additions and 85 deletions
|
|
@ -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)
|
## #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
|
**Status:** DONE (2026-07-04) — **user visual gate PASSED** ("looks good, as close
|
||||||
starvation); AWAITING VISUAL GATE.** Fix #1 (`427332ac`): the per-frame
|
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;
|
`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
|
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
|
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
|
# 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
|
## #163 — Strip the R4-V5 stall-investigation diagnostics
|
||||||
|
|
||||||
**Status:** DONE (2026-07-03, `5ebe2be3`) — removed `[autowalk-gate]` (+
|
**Status:** DONE (2026-07-03, `5ebe2be3`) — removed `[autowalk-gate]` (+
|
||||||
|
|
|
||||||
|
|
@ -4977,29 +4977,6 @@ public sealed class GameWindow : IDisposable
|
||||||
Speed: item.Speed));
|
Speed: item.Speed));
|
||||||
}
|
}
|
||||||
ims.Actions = actionList;
|
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
|
// 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 };
|
{ MovementTypeState: not AcDream.Core.Physics.MovementType.Invalid };
|
||||||
if (!IsPlayerGuid(serverGuid) && rm.HasServerVelocity && !moveToArmed)
|
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;
|
double velocityAge = nowSec - rm.LastServerPosTime;
|
||||||
if (velocityAge > ServerControlledVelocityStaleSeconds)
|
if (velocityAge > ServerControlledVelocityStaleSeconds)
|
||||||
{
|
{
|
||||||
|
|
@ -10015,9 +9989,6 @@ public sealed class GameWindow : IDisposable
|
||||||
// per-node locomotion (turn / RunForward) through the
|
// per-node locomotion (turn / RunForward) through the
|
||||||
// sink. That per-node dispatch is the only motion the
|
// sink. That per-node dispatch is the only motion the
|
||||||
// per-tick update should issue for a remote.
|
// 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);
|
TickRemoteMoveTo(rm);
|
||||||
|
|
||||||
// #170 ROOT FIX (2026-07-04): the per-frame
|
// #170 ROOT FIX (2026-07-04): the per-frame
|
||||||
|
|
|
||||||
|
|
@ -738,12 +738,6 @@ public sealed class MoveToManager
|
||||||
/// (<see cref="PreviousDistance"/>/<see cref="OriginalDistance"/> = dist,
|
/// (<see cref="PreviousDistance"/>/<see cref="OriginalDistance"/> = dist,
|
||||||
/// both times = now).
|
/// both times = now).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
// #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()
|
public void BeginMoveForward()
|
||||||
{
|
{
|
||||||
if (!HasPhysicsObj)
|
if (!HasPhysicsObj)
|
||||||
|
|
@ -762,10 +756,6 @@ public sealed class MoveToManager
|
||||||
|
|
||||||
Params.GetCommand(dist, heading, out uint cmd, out HoldKey holdKey, out bool movingAway);
|
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)
|
if (cmd == 0)
|
||||||
{
|
{
|
||||||
RemovePendingActionsHead();
|
RemovePendingActionsHead();
|
||||||
|
|
@ -826,10 +816,6 @@ public sealed class MoveToManager
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s_mvtoDiag)
|
|
||||||
System.Console.WriteLine(System.FormattableString.Invariant(
|
|
||||||
$"[mvto] BeginTurnToHeading motionsPending={_interp.MotionsPending()} curCmd=0x{CurrentCommand:X8}"));
|
|
||||||
|
|
||||||
if (_interp.MotionsPending())
|
if (_interp.MotionsPending())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
@ -966,10 +952,6 @@ public sealed class MoveToManager
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void UseTime()
|
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 (!HasPhysicsObj || !_contact()) return;
|
||||||
|
|
||||||
if (_pendingActions.First is null) return;
|
if (_pendingActions.First is null) return;
|
||||||
|
|
@ -978,9 +960,6 @@ public sealed class MoveToManager
|
||||||
if (!objectMoveGate) return;
|
if (!objectMoveGate) return;
|
||||||
|
|
||||||
MovementType type = _pendingActions.First.Value.Type;
|
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)
|
if (type == MovementType.MoveToPosition)
|
||||||
{
|
{
|
||||||
HandleMoveToPosition();
|
HandleMoveToPosition();
|
||||||
|
|
@ -1249,10 +1228,6 @@ public sealed class MoveToManager
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void HandleUpdateTarget(TargetInfo info)
|
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)
|
if (!HasPhysicsObj)
|
||||||
{
|
{
|
||||||
CancelMoveTo(WeenieError.NoPhysicsObject);
|
CancelMoveTo(WeenieError.NoPhysicsObject);
|
||||||
|
|
@ -1485,9 +1460,6 @@ public sealed class MoveToManager
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void CancelMoveTo(WeenieError error)
|
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.
|
_ = error; // retail: never read in the body (decomp §7c) — kept for parity/logging.
|
||||||
|
|
||||||
if (MovementTypeState == MovementType.Invalid) return;
|
if (MovementTypeState == MovementType.Invalid) return;
|
||||||
|
|
|
||||||
|
|
@ -2286,34 +2286,9 @@ public sealed class MotionInterpreter : IMotionDoneSink
|
||||||
/// <param name="contextId">Retail <c>arg2</c> — <c>MotionNode.context_id</c>.</param>
|
/// <param name="contextId">Retail <c>arg2</c> — <c>MotionNode.context_id</c>.</param>
|
||||||
/// <param name="motion">Retail <c>arg3</c> — <c>MotionNode.motion</c>.</param>
|
/// <param name="motion">Retail <c>arg3</c> — <c>MotionNode.motion</c>.</param>
|
||||||
/// <param name="jumpErrorCode">Retail <c>arg4</c> — <c>MotionNode.jump_error_code</c>.</param>
|
/// <param name="jumpErrorCode">Retail <c>arg4</c> — <c>MotionNode.jump_error_code</c>.</param>
|
||||||
// #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)
|
public void AddToQueue(uint contextId, uint motion, uint jumpErrorCode)
|
||||||
{
|
{
|
||||||
_pendingMotions.AddLast(new MotionNode(contextId, motion, 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}"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -2363,7 +2338,6 @@ public sealed class MotionInterpreter : IMotionDoneSink
|
||||||
if (head1 is not null)
|
if (head1 is not null)
|
||||||
{
|
{
|
||||||
_pendingMotions.RemoveFirst();
|
_pendingMotions.RemoveFirst();
|
||||||
if (s_drainDiag) s_doneCount++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue