NEO-93: Fix delta cap LastAdvancedUtc to preserve gradual catch-up.

When simulation is capped, advance LastAdvancedUtc to windowEnd instead
of nowUtc so subsequent polls do not burst through missed NPC cycles.

Co-authored-by: Cursor <cursoragent@cursor.com>
pull/131/head
VinPropane 2026-05-27 23:16:35 -04:00
parent 4fcbb99881
commit 056b0e77f0
3 changed files with 20 additions and 2 deletions

View File

@ -61,7 +61,7 @@
- Holder-only idle→aggro sync from **`IThreatStateStore`**; no proximity auto-aggro.
- **`attack_execute`** chains instantly to **`recover`** within the same advance step (no player damage — NEO-95).
- Dev **`combat-targets-fixture`** resets runtime rows alongside HP + threat.
- **22** NEO-93-focused tests green (`NpcRuntimeOperationsTests`, `InMemoryNpcRuntimeStateStoreTests`, fixture extension).
- **23** NEO-93-focused tests green (`NpcRuntimeOperationsTests`, `InMemoryNpcRuntimeStateStoreTests`, fixture extension).
## Technical approach

View File

@ -239,5 +239,23 @@ public sealed class NpcRuntimeOperationsTests
runtime.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
Assert.Equal(NpcBehaviorState.Recover, snapshot.BehaviorState);
Assert.Equal(T0.AddSeconds(4.5), snapshot.PhaseStartedUtc);
Assert.Equal(T0.AddSeconds(5), runtime.LastAdvancedUtc);
}
[Fact]
public void AdvanceAll_ShouldPreserveGradualCatchUp_AfterLongGapWithDeltaCap()
{
// Arrange
var (runtime, threat, behavior) = CreateFixture();
SetHolder(threat, PrototypeNpcRegistry.PrototypeNpcMeleeId);
Advance(T0, runtime, threat, behavior);
Advance(T0.AddSeconds(100), runtime, threat, behavior, maxDeltaSeconds: 5);
// Act
Advance(T0.AddSeconds(100.5), runtime, threat, behavior, maxDeltaSeconds: 5);
// Assert
Assert.Equal(T0.AddSeconds(10), runtime.LastAdvancedUtc);
runtime.TryGet(PrototypeNpcRegistry.PrototypeNpcMeleeId, out var snapshot);
Assert.Equal(NpcBehaviorState.Recover, snapshot.BehaviorState);
Assert.Equal(T0.AddSeconds(9), snapshot.PhaseStartedUtc);
}
}

View File

@ -72,7 +72,7 @@ public static class NpcRuntimeOperations
behaviorRegistry);
}
runtimeStore.LastAdvancedUtc = nowUtc;
runtimeStore.LastAdvancedUtc = windowEnd;
}
/// <summary>Resets all prototype NPC runtime rows to idle (dev fixture).</summary>