acdream/tests/AcDream.Runtime.Tests/Session/RuntimeAcceptedPositionDriveControllerTests.cs
Erik 7f1c1f5aa6 feat(physics): C4 route 4b-2 — remote far snap through the canonical placement
Flips the SetPositionSimple classification (contact, PlayerDistance >= 96 m) for
remotes onto 4b-1's drive controller and deletes both legacy far blocks, both
duplicated 96f/4f constant pairs, and both `?? Vector3.Zero` fabrications. The
4 m constant now exists exactly once. Teleport and cell-less stay legacy for
4b-3.

Retail: MoveOrTeleport @0x00516330's far branch runs StopInterpolating
@0x005163CB before SetPositionSimple @0x005163D9 and returns 1 @0x005163E8
regardless — the SetPositionError is discarded — so HandleReceivedPosition arms
ConstrainTo @0x00454272 post-move on commit AND on failure. The x87 parity
decode at @0x00516393-@0x0051639E puts exactly 96.0 on the far branch.
SetPositionSimple @0x005162B0 builds flags 0x1012 at @0x005162C4.

Non-commit outcomes still advance the body, because retail's SetPositionInternal
@0x00515BD0 commits the destination via store_position @0x00515CE2 when no cell
resolves. The partition is by STAGE, not heuristic, enforced by an exhaustive
switch: Refused/Contention/NotApplicable/RejectedPreparation store (the placement
never executed); Committed/Deferred/RejectedByPlacement do not (the engine ran
and refused, matching retail's non-storing returns @0x00515CB2 and @0x00515CD5).
Without this a refused far snap froze the remote with an emptied queue.

Also fixes a shipped defect this route made live: ParkDeferred's quiescence parks
withdrew the entity (InWorld=false, clock suspended, residency removed) and were
never restorable, while Forget(restoreCancelledPark: true) runs for every
accepted Position on every entity. The restorable decision now lives inside
ParkDeferred AFTER SnapToCell, reading body.CellPosition.ObjCellId — the value
RestoreParkWithdrawal actually restores at — against every live quiescence
rather than one minimum-OperationId token. The three pre-snap fields are hoisted
into locals because SnapToCell ends with InWorld = true. ParkCollisionResidents
passes restorableOnCancel: false explicitly; the plain unplaceable park is
provably unchanged. RestoreParkWithdrawal re-tests the prefix at restore time so
a retained route-2 park cannot re-admit into a prefix that began quiescing
during the park.

CanAttemptDestination is retained as an OPTIMISATION only, with the two Core
predicates it cannot reproduce written down at the pre-flight, plus the two
properties that depend on it staying there.

Four fix rounds and eight Opus reviews. The slice was fully green at 10,990,
10,997 and 11,004 while containing real defects — a frozen remote pinned as
correct by its own test, a fallback that over-wrote on the exact retail paths
that decline to store, and a park guard incomplete on two independent axes.

Register: AP-137 (leftover classifications take AP-87's catch-up; states the
cell-less enqueue-vs-place delta deferred to 4b-3, that RejectedData is applied
anyway, and the headless divergence), AP-138 (the refusable far placement),
AP-136 narrowed to match the relocation. #309's acceptance steps rewritten —
step 5 previously asserted a recovery the code does not perform — and gated on a
new ACDREAM_PROBE_PARK=1 signal so the check cannot pass while broken.

Suite 11,009 passed / 4 skipped / 0 failed against a measured 10,968 baseline.
The 10,973 figure recorded earlier was wrong and is corrected here.

Connected gate outstanding: the two-client far-snap walk and #309.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 07:55:56 +02:00

1831 lines
78 KiB
C#

using System.Net;
using System.Numerics;
using AcDream.Core.Combat;
using AcDream.Core.Items;
using AcDream.Core.Net;
using AcDream.Core.Net.Messages;
using AcDream.Core.Physics;
using AcDream.Core.Spells;
using AcDream.Runtime.Entities;
using AcDream.Runtime.Gameplay;
using AcDream.Runtime.Physics;
using AcDream.Runtime.Session;
using AcDream.Runtime.World;
namespace AcDream.Runtime.Tests.Session;
/// <summary>
/// C4 route 2 (2026-08-03): the Runtime-owned accepted-Position execution
/// seam for a ForcePosition on an already-live local player. Fixture
/// construction mirrors <c>RuntimeLiveEntitySessionControllerTests</c>'
/// session/first-entry harness — a live <see cref="PlayerMovementController"/>
/// only exists once the local player's initial-Create residence has fully
/// drained through <see cref="RuntimeFirstEntryDriveController"/>.
/// </summary>
public sealed class RuntimeAcceptedPositionDriveControllerTests
{
private const uint PlayerGuid = 0x50000001u;
private const uint SpawnLandblock = 0x01010000u;
private const float SpawnHeight = 5f;
/// <summary>
/// A landblock whose collision generation is deliberately NEVER committed
/// in this fixture — the same id the deferred-park tests below use. The
/// pre-engine quiescence check runs ahead of the engine and therefore
/// ahead of any collision-readiness question, so its readiness is
/// irrelevant to the round-3 destination-quiescence test.
/// </summary>
private const uint DestinationLandblock = 0x02020000u;
/// <summary>
/// <see cref="SpawnLandblock"/>'s +X neighbour: landblock ids pack the
/// block X index in bits 24-31, so 0x0101 → 0x0201 is one block east, and
/// <c>LandDefs.LcoordToGid</c> re-derives exactly this prefix for a global
/// lcoord one cell past the 192 m seam.
/// </summary>
private const uint NeighbourLandblock = 0x02010000u;
/// <summary>
/// Cell (7, 0) of <see cref="SpawnLandblock"/> — block-local X in
/// [168, 192), Y in [0, 24). <c>LandDefs.GidToLcoord</c>'s inverse:
/// <c>low = (ly &amp; 7) + ((lx &amp; 7) &lt;&lt; 3) + 1 = 0 + 56 + 1 = 57</c>.
/// </summary>
private const uint SpawnSeamCell = SpawnLandblock | 57u;
[Fact]
public void NotApplicable_WhenDispositionIsNotForcePosition()
{
using StartedRuntime started = StartRuntime();
(RuntimeEntityRecord record, PlayerMovementController controller) =
EnterLocalPlayer(started.Runtime);
RuntimeAcceptedPositionDriveController drive =
CreateAcceptedPositionDrive(started.Runtime, out List<byte[]> gameActions);
RuntimeAcceptedPositionExecutionStatus status =
drive.TryExecuteAcceptedLocalPosition(
record,
ForceUpdate(new Vector3(30f, 30f, 5f)),
PositionTimestampDisposition.Apply,
Timestamps(teleport: 0),
previousTeleportSequence: 0);
Assert.Equal(RuntimeAcceptedPositionExecutionStatus.NotApplicable, status);
Assert.Empty(gameActions);
}
[Fact]
public void NotApplicable_WhenRecordIsNotTheLocalPlayer()
{
using StartedRuntime started = StartRuntime();
(RuntimeEntityRecord record, _) = EnterLocalPlayer(started.Runtime);
RuntimeAcceptedPositionDriveController drive =
CreateAcceptedPositionDrive(started.Runtime, out _);
// Same record, but the drive's own local-player-guid accessor no
// longer matches it (as if it belonged to some other entity).
started.Runtime.PlayerIdentity.ServerGuid = 0x70000099u;
RuntimeAcceptedPositionExecutionStatus status =
drive.TryExecuteAcceptedLocalPosition(
record,
ForceUpdate(new Vector3(30f, 30f, 5f)),
PositionTimestampDisposition.ForcePosition,
Timestamps(teleport: 0),
previousTeleportSequence: 0);
Assert.Equal(RuntimeAcceptedPositionExecutionStatus.NotApplicable, status);
}
[Fact]
public void NotApplicable_WhileAnInitialCreateResidenceIsStillActive()
{
using StartedRuntime started = StartRuntime();
GameRuntime runtime = started.Runtime;
runtime.PlayerIdentity.ServerGuid = PlayerGuid;
CommitLandblockCollision(runtime, SpawnLandblock);
RuntimeEntityRecord record = runtime.EntityObjects
.RegisterEntityWithInitialResidence(
Spawn(PlayerGuid), isLocalPlayer: true)
.Canonical!;
// Deliberately do NOT drain the first-entry drive: the residence
// (and hence no PhysicsBody/controller) is still open — route 1's
// job, never route 2's.
RuntimeAcceptedPositionDriveController drive =
CreateAcceptedPositionDrive(runtime, out List<byte[]> gameActions);
RuntimeAcceptedPositionExecutionStatus status =
drive.TryExecuteAcceptedLocalPosition(
record,
ForceUpdate(new Vector3(30f, 30f, 5f)),
PositionTimestampDisposition.ForcePosition,
Timestamps(teleport: 0),
previousTeleportSequence: 0);
Assert.Equal(RuntimeAcceptedPositionExecutionStatus.NotApplicable, status);
Assert.Empty(gameActions);
}
[Fact]
public void Rejected_WhenTheClassifierDeclinesTheFrame()
{
using StartedRuntime started = StartRuntime();
(RuntimeEntityRecord record, PlayerMovementController controller) =
EnterLocalPlayer(started.Runtime);
Vector3 positionBefore = controller.Position;
RuntimeAcceptedPositionDriveController drive =
CreateAcceptedPositionDrive(started.Runtime, out List<byte[]> gameActions);
// RuntimeAuthoritativePositionRouteClassifier.ValidAcceptedAuthority's
// ForcePosition case requires PreviousTeleportSequence ==
// AcceptedTeleportSequence; a mismatch is a genuine data-validity
// rejection (this call site never re-derives the timestamp gate's
// own freshness rule — it is asserting the classifier's own
// independent structural check).
RuntimeAcceptedPositionExecutionStatus status =
drive.TryExecuteAcceptedLocalPosition(
record,
ForceUpdate(new Vector3(30f, 30f, 5f)),
PositionTimestampDisposition.ForcePosition,
Timestamps(teleport: 6),
previousTeleportSequence: 5);
Assert.Equal(RuntimeAcceptedPositionExecutionStatus.Rejected, status);
Assert.Equal(positionBefore, controller.Position);
Assert.Empty(gameActions);
AssertConverged(started.Runtime);
}
[Fact]
public void Committed_MovesTheBodyPreservesHeadingAndAcksExactlyOnceAfterCommit()
{
using StartedRuntime started = StartRuntime();
GameRuntime runtime = started.Runtime;
(RuntimeEntityRecord record, PlayerMovementController controller) =
EnterLocalPlayer(runtime);
Quaternion headingBeforeCorrection = controller.BodyOrientation;
var corrected = new Vector3(30f, 32f, 5f);
WorldSession.EntityPositionUpdate wire = ForceUpdate(corrected);
// A deliberately different wire rotation than the controller's own
// heading, exactly like a real server correction carries whatever
// heading it last observed — proves the seam never applies a SECOND
// heading substitution on top of the one the upstream merge already
// performed (contract §1c: RuntimeEntityObjectLifetime.TryApplyPosition's
// forcePositionRotation argument, exercised for real below via
// MergeAccepted).
wire = wire with
{
Position = wire.Position with
{
RotationX = 0f,
RotationY = 0f,
RotationZ = 1f,
RotationW = 0f,
},
};
(PositionTimestampDisposition disposition, AcceptedPhysicsTimestamps timestamps) =
MergeAccepted(runtime, controller, wire);
Assert.Equal(PositionTimestampDisposition.ForcePosition, disposition);
RuntimeAcceptedPositionDriveController drive =
CreateAcceptedPositionDrive(runtime, out List<byte[]> gameActions);
RuntimeAcceptedPositionExecutionStatus status =
drive.TryExecuteAcceptedLocalPosition(
record,
wire,
disposition,
timestamps,
timestamps.PreviousTeleport);
Assert.Equal(RuntimeAcceptedPositionExecutionStatus.Committed, status);
Assert.Equal(corrected, controller.Position);
Assert.Equal(headingBeforeCorrection, controller.BodyOrientation);
Assert.Single(gameActions);
AssertConverged(runtime);
}
[Fact]
public void Contention_WhenTheEntityAlreadyOwnsAnActiveOperation()
{
using StartedRuntime started = StartRuntime();
GameRuntime runtime = started.Runtime;
(RuntimeEntityRecord record, PlayerMovementController controller) =
EnterLocalPlayer(runtime);
Vector3 positionBefore = controller.Position;
WorldSession.EntityPositionUpdate wire =
ForceUpdate(new Vector3(30f, 32f, 5f));
(PositionTimestampDisposition disposition, AcceptedPhysicsTimestamps timestamps) =
MergeAccepted(runtime, controller, wire);
Assert.Equal(PositionTimestampDisposition.ForcePosition, disposition);
// Mirrors the displaced-authority scenario the deleted
// LocalForcePositionTransaction's trailing isCurrent() covered: some
// OTHER operation is already in flight for this exact entity (e.g. a
// remote-authoritative resolve mid-transaction) when the
// ForcePosition arrives.
RuntimeEntityPlacementToken displaced = runtime.EntityObjects.Physics
.SetPosition.TryBeginExclusiveAuthoredPlacement(
record,
record.PositionAuthorityVersion,
RuntimeSetPositionOperationKind.LocalAuthoritative);
Assert.True(displaced.IsValid);
RuntimeAcceptedPositionDriveController drive =
CreateAcceptedPositionDrive(runtime, out List<byte[]> gameActions);
RuntimeAcceptedPositionExecutionStatus status =
drive.TryExecuteAcceptedLocalPosition(
record,
wire,
disposition,
timestamps,
timestamps.PreviousTeleport);
Assert.Equal(RuntimeAcceptedPositionExecutionStatus.Contention, status);
Assert.Equal(positionBefore, controller.Position);
Assert.Empty(gameActions);
// Cleanup: release the displaced operation so the fixture converges.
RuntimePlacementCancellationReceipt cancellation = runtime.EntityObjects
.Physics.SetPosition.ForgetExactPlacement(displaced);
if (cancellation.IsValid)
{
runtime.EntityObjects.Physics.SetPosition
.PublishCancellation(cancellation);
}
}
[Fact]
public void DeferredCell_ParksThenCommitsAndNeverDoubleAcksAfterTheCollisionGenerationWakes()
{
using StartedRuntime started = StartRuntime();
GameRuntime runtime = started.Runtime;
(RuntimeEntityRecord record, PlayerMovementController controller) =
EnterLocalPlayer(runtime);
RuntimeAcceptedPositionDriveController drive =
CreateAcceptedPositionDrive(runtime, out List<byte[]> gameActions);
// A destination landblock whose collision generation was never
// committed (mirrors RuntimeSetPositionStateTests' CrossLandblockRequest
// pattern — re-admitting an ALREADY-ready landblock through this
// simple Begin/CommitCollisionGeneration pair does not block a new
// placement; only a genuinely fresh landblock does) parks the
// operation instead of committing it. Runtime's world-frame
// resolution is arithmetic once ANY frame is observed
// (RuntimePhysicsState.TryGetWorldFrameOffset:598-617), so this
// parks on collision readiness specifically, not on an unresolved
// frame.
const uint deferredLandblock = 0x02020000u;
var deferredPosition = new Vector3(10f, 10f, SpawnHeight);
WorldSession.EntityPositionUpdate parkedUpdate = ForceUpdate(
deferredPosition,
landblockId: deferredLandblock | 0x0001u);
(PositionTimestampDisposition disposition, AcceptedPhysicsTimestamps timestamps) =
MergeAccepted(runtime, controller, parkedUpdate);
Assert.Equal(PositionTimestampDisposition.ForcePosition, disposition);
RuntimeAcceptedPositionExecutionStatus parked =
drive.TryExecuteAcceptedLocalPosition(
record,
parkedUpdate,
disposition,
timestamps,
timestamps.PreviousTeleport);
Assert.Equal(RuntimeAcceptedPositionExecutionStatus.DeferredCell, parked);
Assert.Empty(gameActions);
Assert.Equal(1, drive.PendingCount);
// Advance() before the destination is ready makes no progress.
drive.Advance();
Assert.Empty(gameActions);
Assert.Equal(1, drive.PendingCount);
CommitLandblockCollision(runtime, deferredLandblock);
// Production always has a LIVE host subscription
// (RuntimePlacementProjectionSubscription) that applies-and-
// acknowledges the resubmitted Place synchronously the instant
// RetryDeferred's CommitCanonical publishes it — that is what
// promotes this controller's own Watch into an observable
// acknowledged completion (RuntimeSetPositionState.AcknowledgeProjection's
// Place branch). This bare-Runtime fixture has no host wired, so it
// stands in for that subscription exactly like
// RuntimeLiveEntitySessionControllerTests' own DrainPlacementFifo.
DrainPlacementFifo(runtime);
// A single Advance() pump resolves the deferred commit.
drive.Advance();
Assert.Equal(0, drive.PendingCount);
// World position, not the cell-local wire position: the deferred
// landblock (0x0202) sits one landblock diagonally from the spawn
// landblock (0x0101) in Runtime's world frame, a (192, 192, 0) m
// offset (RuntimePhysicsState.TryGetWorldFrameOffset).
Assert.Equal(deferredPosition + new Vector3(192f, 192f, 0f), controller.Position);
// R8 review fix (2026-08-03): the ack is gated on retail's own
// independent CanSendPositionEvent requirement (Contact + OnWalkable
// — PlayerMovementController.cs:1517). Measured directly: this
// synthetic cross-landblock jump resolves with InContact=false in
// this bare-Runtime fixture (no subsequent physics tick runs here to
// sweep the body onto the terrain it was placed exactly tangent to —
// unlike the WITHIN-landblock move
// Committed_MovesTheBodyPreservesHeadingAndAcksExactlyOnceAfterCommit
// exercises, which measures Contact=true and DOES get its ack). This
// test therefore does NOT verify the single-ack-after-wake sequence
// end to end — it only proves the non-double-ack invariant below.
// Asserting exactly one ack here would require driving a real
// physics tick after the wake to establish ground contact, which is
// out of this fixture's scope; do not report this sequence as
// ack-verified (docs/ISSUES.md #285) until a harness does that.
int acksAfterFirstResolve = gameActions.Count;
// Further pumps are no-ops — the ack must never fire twice, however
// many times Advance() is pumped (still true wants Contact to
// eventually flip and the ack to fire exactly once, whenever that
// happens).
drive.Advance();
drive.Advance();
Assert.Equal(acksAfterFirstResolve, gameActions.Count);
AssertConverged(runtime);
}
/// <summary>
/// Round 2 unified rule, branch 1 of 3 — <b>EQUAL</b>. The parked
/// operation dies (here through the exact
/// <c>RuntimeSetPositionState.Forget</c> funnel every mid-session
/// cancellation shares: supersession, the lost-cell deadline,
/// <c>ParkCollisionResidents</c>, a generation change) while NO newer
/// accepted position has taken the authority, so the record's
/// <c>PositionAuthorityVersion</c> still equals the dead operation's own.
/// Nothing is outstanding: <c>_pending</c> clears, and the drive must NOT
/// re-issue. Re-issuing on an unchanged authority is precisely the shape
/// that produced N1's second placement + second ack.
/// </summary>
[Fact]
public void Equal_ClearsPendingWithoutReissuingWhenNoNewerAcceptedAuthorityArrived()
{
using StartedRuntime started = StartRuntime();
GameRuntime runtime = started.Runtime;
(RuntimeEntityRecord record, PlayerMovementController controller) =
EnterLocalPlayer(runtime);
RuntimeAcceptedPositionDriveController drive =
CreateAcceptedPositionDrive(runtime, out List<byte[]> gameActions);
const uint deferredLandblock = 0x02020000u;
var deferredPosition = new Vector3(10f, 10f, SpawnHeight);
WorldSession.EntityPositionUpdate parkedUpdate = ForceUpdate(
deferredPosition,
landblockId: deferredLandblock | 0x0001u);
(PositionTimestampDisposition disposition, AcceptedPhysicsTimestamps timestamps) =
MergeAccepted(runtime, controller, parkedUpdate);
Assert.Equal(PositionTimestampDisposition.ForcePosition, disposition);
RuntimeAcceptedPositionExecutionStatus parked =
drive.TryExecuteAcceptedLocalPosition(
record,
parkedUpdate,
disposition,
timestamps,
timestamps.PreviousTeleport);
Assert.Equal(RuntimeAcceptedPositionExecutionStatus.DeferredCell, parked);
Assert.Equal(1, drive.PendingCount);
ulong authorityAtPark = record.PositionAuthorityVersion;
Vector3 positionAtPark = controller.Position;
RuntimePlacementCancellationReceipt cancellation =
runtime.EntityObjects.Physics.SetPosition.Forget(record);
if (cancellation.IsValid)
{
runtime.EntityObjects.Physics.SetPosition
.PublishCancellation(cancellation);
}
// The precondition this branch is defined by: a bare Forget cancels
// the operation WITHOUT merging anything, so the accepted authority
// has not moved.
Assert.Equal(authorityAtPark, record.PositionAuthorityVersion);
drive.Advance();
// No re-issue: a re-issue against this still-unready destination would
// park AGAIN and leave PendingCount at 1 (that is exactly what the
// round-1 shape did here).
Assert.Equal(0, drive.PendingCount);
Assert.Equal(positionAtPark, controller.Position);
// Round 3 (2026-08-03): the packet's placement WAS begun and then
// died without committing, so retail's unconditional position event is
// owed and goes out here carrying the unchanged pose
// (SmartBox::BlipPlayer @0x00453940 discards SetPositionSimple's
// error; SmartBox::HandleReceivedPosition @0x00453FD0 acks at
// @0x00454091 regardless). Before round 3 this asserted Empty, which
// encoded the defect: neither the body moved NOR an ack left.
Assert.Single(gameActions);
// Repeated pumps stay silent — the funnel cleared, it did not park a
// retry marker for an authority nothing is waiting on, and retail
// never retries a force that failed.
drive.Advance();
drive.Advance();
Assert.Equal(0, drive.PendingCount);
Assert.Single(gameActions);
Assert.Equal(positionAtPark, controller.Position);
AssertConverged(runtime);
}
/// <summary>
/// Round 2 unified rule, branch 2 of 3 — <b>ADVANCED, newest accepted
/// event is still a ForcePosition</b>; also the B1 regression. Exact
/// production shape: a park wakes and its <c>Place</c> is ACCEPTED, so the
/// operation leaves <c>_operations</c> but its completion is RETAINED;
/// <c>Forget</c> then early-returns
/// (<c>RuntimeSetPositionState.CancelCoreDeferred</c>'s
/// <c>_operations.Remove</c> guard) and the retained completion survives
/// the next packet's merge. That next ForcePosition therefore cannot
/// begin (<c>HasRetainedCompletion</c> → <c>Contention</c>) — and before
/// the unified funnel its correction was lost outright, because the next
/// pump consumed the OLD completion and acked the OLD pose with nothing
/// left pointing at the new one. The one-frame window is real on the
/// graphical host, whose inbound dispatch precedes <c>RetryPending</c>.
/// </summary>
[Fact]
public void Advanced_ReissuesWhenTheNewestAcceptedEventIsStillAForcePosition()
{
using StartedRuntime started = StartRuntime();
GameRuntime runtime = started.Runtime;
(RuntimeEntityRecord record, PlayerMovementController controller) =
EnterLocalPlayer(runtime);
RuntimeAcceptedPositionDriveController drive =
CreateAcceptedPositionDrive(runtime, out List<byte[]> gameActions);
const uint deferredLandblock = 0x02020000u;
var firstCorrection = new Vector3(10f, 10f, SpawnHeight);
WorldSession.EntityPositionUpdate parkedUpdate = ForceUpdate(
firstCorrection,
landblockId: deferredLandblock | 0x0001u);
(PositionTimestampDisposition parkedDisposition,
AcceptedPhysicsTimestamps parkedTimestamps) =
MergeAccepted(runtime, controller, parkedUpdate);
Assert.Equal(
PositionTimestampDisposition.ForcePosition, parkedDisposition);
Assert.Equal(
RuntimeAcceptedPositionExecutionStatus.DeferredCell,
drive.TryExecuteAcceptedLocalPosition(
record,
parkedUpdate,
parkedDisposition,
parkedTimestamps,
parkedTimestamps.PreviousTeleport));
// The park wakes and its Place is accepted, leaving a RETAINED
// completion. Deliberately no Advance() yet: this is the host frame in
// which the next packet arrives before the pump runs.
CommitLandblockCollision(runtime, deferredLandblock);
DrainPlacementFifo(runtime);
var secondCorrection = new Vector3(14f, 12f, SpawnHeight);
WorldSession.EntityPositionUpdate secondUpdate = ForceUpdate(
secondCorrection,
landblockId: deferredLandblock | 0x0001u,
positionSequence: 3,
forcePositionSequence: 2);
(PositionTimestampDisposition secondDisposition,
AcceptedPhysicsTimestamps secondTimestamps) =
MergeAccepted(runtime, controller, secondUpdate);
Assert.Equal(
PositionTimestampDisposition.ForcePosition, secondDisposition);
Assert.Equal(
RuntimeAcceptedPositionExecutionStatus.Contention,
drive.TryExecuteAcceptedLocalPosition(
record,
secondUpdate,
secondDisposition,
secondTimestamps,
secondTimestamps.PreviousTeleport));
// One pump: consume the older completion (its own reconcile + ack),
// then re-issue the newest accepted force — which the funnel proves by
// landing the body on the SECOND correction, not the first.
drive.Advance();
Assert.Equal(0, drive.PendingCount);
Assert.Equal(
secondCorrection + new Vector3(192f, 192f, 0f),
controller.Position);
// Round 3 (2026-08-03): the former `gameActions.Count <= 2` assertion
// was deleted here. It could not fail: this fixture's
// CommitLandblockCollision adds BOTH landblocks at worldOffsetX/Y 0f
// while Runtime's world frame places the deferred landblock at
// +192/+192, so the body lands over no terrain, resolves with
// InContact=false, and retail's own CanSendPositionEvent gate
// suppresses every ack — gameActions.Count is 0 here. It was also far
// too loose to encode "at most one per packet". The real
// discriminators (body landed on the SECOND correction, PendingCount)
// remain; the ack-count contract is pinned by
// TerminalWithoutCommit_SendsExactlyOnePositionEventAndLeavesTheBodyUnmoved
// and Committed_SendsExactlyOnePositionEventAcrossTheCommitAndTheSettle,
// whose fixtures genuinely satisfy the contact gate.
// Further pumps are no-ops: the funnel settled on the Equal branch.
drive.Advance();
Assert.Equal(0, drive.PendingCount);
Assert.Equal(
secondCorrection + new Vector3(192f, 192f, 0f),
controller.Position);
AssertConverged(runtime);
}
/// <summary>
/// Round 2 unified rule, branch 3 of 3 — <b>ADVANCED, newest accepted
/// event is an ordinary Apply</b> (N2). The park is cancelled by the
/// ordinary echo's own merge-time <c>Forget</c>, and that echo — not the
/// force — now owns the accepted pose. Re-issuing here would apply the
/// force route's <c>Teleport|Slide</c> flags to an ordinary pose, send an
/// ack retail never sends on that branch, and skip the <c>ConstrainTo</c>
/// the ordinary branch runs
/// (<c>RuntimeAuthoritativePositionRouteClassifier.cs:368-388</c>). So the
/// funnel must clear without placing and without acking.
/// </summary>
[Fact]
public void Advanced_DoesNotReissueWhenTheNewestAcceptedEventIsAnOrdinaryApply()
{
using StartedRuntime started = StartRuntime();
GameRuntime runtime = started.Runtime;
(RuntimeEntityRecord record, PlayerMovementController controller) =
EnterLocalPlayer(runtime);
RuntimeAcceptedPositionDriveController drive =
CreateAcceptedPositionDrive(runtime, out List<byte[]> gameActions);
const uint deferredLandblock = 0x02020000u;
WorldSession.EntityPositionUpdate parkedUpdate = ForceUpdate(
new Vector3(10f, 10f, SpawnHeight),
landblockId: deferredLandblock | 0x0001u);
(PositionTimestampDisposition parkedDisposition,
AcceptedPhysicsTimestamps parkedTimestamps) =
MergeAccepted(runtime, controller, parkedUpdate);
Assert.Equal(
PositionTimestampDisposition.ForcePosition, parkedDisposition);
Assert.Equal(
RuntimeAcceptedPositionExecutionStatus.DeferredCell,
drive.TryExecuteAcceptedLocalPosition(
record,
parkedUpdate,
parkedDisposition,
parkedTimestamps,
parkedTimestamps.PreviousTeleport));
Assert.Equal(1, drive.PendingCount);
ulong authorityAtPark = record.PositionAuthorityVersion;
Vector3 positionAtPark = controller.Position;
// ACE's next ordinary broadcast, ~100-200 ms later. It merges (which
// Forgets the park and advances the accepted authority) and is NEVER
// dispatched to this route — both hosts gate the dispatch on
// ForcePosition.
var ordinaryPose = new Vector3(31f, 33f, SpawnHeight);
(PositionTimestampDisposition ordinaryDisposition, _) = MergeAccepted(
runtime,
controller,
OrdinaryUpdate(ordinaryPose, positionSequence: 3));
Assert.Equal(PositionTimestampDisposition.Apply, ordinaryDisposition);
Assert.NotEqual(authorityAtPark, record.PositionAuthorityVersion);
drive.Advance();
Assert.Equal(0, drive.PendingCount);
// The force route never ran again: the body is exactly where the
// cancelled park left it, and specifically NOT on the ordinary echo's
// pose — which is what a re-issue would have placed it on, with the
// force route's Teleport|Slide flags and no ConstrainTo.
Assert.Equal(positionAtPark, controller.Position);
Assert.NotEqual(ordinaryPose, controller.Position);
// Exactly ONE AutonomousPosition, and it belongs to the FORCE packet,
// not the ordinary echo: the force's placement was begun and died
// without committing, which retail still acknowledges
// (SmartBox::HandleReceivedPosition @0x00453FD0 acks @0x00454091 with
// whatever SetPositionSimple left the body at). The ordinary echo
// never reaches this route at all — retail's ordinary branch has no
// unconditional SendPositionEvent. Round 3 (2026-08-03) corrected this
// from Empty, which encoded the lost-ack defect.
Assert.Single(gameActions);
drive.Advance();
Assert.Equal(0, drive.PendingCount);
Assert.Equal(positionAtPark, controller.Position);
Assert.Single(gameActions);
AssertConverged(runtime);
}
/// <summary>
/// N1 regression (2026-08-03): ONE server correction must produce EXACTLY
/// one canonical placement and EXACTLY one outbound
/// <c>AutonomousPosition</c> — never two. The round-1 shape left a dead
/// <c>_pending</c> entry behind whenever a fresh packet's own placement
/// committed while an older park was still tracked, and the next pump
/// re-issued from that dead entry: a second placement and a second ack for
/// a single correction, which is the exact duplicate-authority class
/// <c>670f307c</c> deleted and this whole slice exists to remove.
/// </summary>
[Fact]
public void OneServerCorrectionProducesExactlyOnePlacementAndOneAck()
{
using StartedRuntime started = StartRuntime();
GameRuntime runtime = started.Runtime;
(RuntimeEntityRecord record, PlayerMovementController controller) =
EnterLocalPlayer(runtime);
RuntimeAcceptedPositionDriveController drive =
CreateAcceptedPositionDrive(runtime, out List<byte[]> gameActions);
// An earlier force parks on a landblock whose collision is not ready.
const uint deferredLandblock = 0x02020000u;
WorldSession.EntityPositionUpdate parkedUpdate = ForceUpdate(
new Vector3(10f, 10f, SpawnHeight),
landblockId: deferredLandblock | 0x0001u);
(PositionTimestampDisposition parkedDisposition,
AcceptedPhysicsTimestamps parkedTimestamps) =
MergeAccepted(runtime, controller, parkedUpdate);
Assert.Equal(
RuntimeAcceptedPositionExecutionStatus.DeferredCell,
drive.TryExecuteAcceptedLocalPosition(
record,
parkedUpdate,
parkedDisposition,
parkedTimestamps,
parkedTimestamps.PreviousTeleport));
Assert.Equal(1, drive.PendingCount);
Assert.Empty(gameActions);
// THE one server correction under test: a second force, into the
// already-ready spawn landblock, so it commits synchronously. Its
// merge Forgets the park.
var corrected = new Vector3(30f, 32f, SpawnHeight);
WorldSession.EntityPositionUpdate correction = ForceUpdate(
corrected,
positionSequence: 3,
forcePositionSequence: 2);
(PositionTimestampDisposition disposition, AcceptedPhysicsTimestamps timestamps) =
MergeAccepted(runtime, controller, correction);
Assert.Equal(PositionTimestampDisposition.ForcePosition, disposition);
Assert.Equal(
RuntimeAcceptedPositionExecutionStatus.Committed,
drive.TryExecuteAcceptedLocalPosition(
record,
correction,
disposition,
timestamps,
timestamps.PreviousTeleport));
Assert.Equal(0, drive.PendingCount);
Assert.Single(gameActions);
Assert.Equal(corrected, controller.Position);
ulong placementsAfterCorrection = record.PlacementCommitVersion;
// Every subsequent pump must be a no-op. Before the fix the FIRST of
// these re-issued the dead park entry: PlacementCommitVersion advanced
// again and a SECOND AutonomousPosition left for the same correction.
drive.Advance();
drive.Advance();
Assert.Equal(0, drive.PendingCount);
Assert.Single(gameActions);
Assert.Equal(corrected, controller.Position);
Assert.Equal(placementsAfterCorrection, record.PlacementCommitVersion);
AssertConverged(runtime);
}
/// <summary>
/// Round 3 blocker (2026-08-03) — <b>the terminal-without-commit ack</b>.
/// Retail attempts the placement, and if it fails the body simply does not
/// move — but the packet is acknowledged regardless and never retried:
/// <c>SmartBox::BlipPlayer</c> @0x00453940 calls
/// <c>CPhysicsObj::SetPositionSimple</c> @0x005162B0, which returns an
/// <c>enum SetPositionError</c> that other retail sites test
/// (<c>== OK_SPE</c> @0x0055605D) and that <c>BlipPlayer</c> DISCARDS;
/// <c>BlipPlayer</c> returns <c>void</c>, and its caller
/// <c>SmartBox::HandleReceivedPosition</c> @0x00453FD0 then runs
/// <c>cmdinterp-&gt;SendPositionEvent()</c> @0x00454091 unconditionally
/// before returning @0x0045409D.
///
/// Unlike
/// <see cref="Equal_ClearsPendingWithoutReissuingWhenNoNewerAcceptedAuthorityArrived"/>
/// (whose subject is the no-re-issue decision) this test's subject is the
/// ack contract itself: EXACTLY one outbound <c>AutonomousPosition</c> for
/// the failed packet, carrying whatever pose the retired operation left
/// behind, with no further placement performed by the settle. Before round
/// 3 this path sent zero — the correction never took AND the server was
/// never told it had not taken.
/// </summary>
[Fact]
public void TerminalWithoutCommit_SendsExactlyOnePositionEventAndLeavesTheBodyUnmoved()
{
using StartedRuntime started = StartRuntime();
GameRuntime runtime = started.Runtime;
(RuntimeEntityRecord record, PlayerMovementController controller) =
EnterLocalPlayer(runtime);
RuntimeAcceptedPositionDriveController drive =
CreateAcceptedPositionDrive(runtime, out List<byte[]> gameActions);
// The body sits on the spawn landblock's flat terrain, so retail's own
// CanSendPositionEvent admission (Contact + OnWalkable) is genuinely
// satisfied — this fixture can observe the ack rather than silently
// measuring a suppression.
Assert.True(controller.CanSendPositionEvent);
// A force whose destination landblock has no published collision
// generation parks instead of committing.
const uint deferredLandblock = 0x02020000u;
WorldSession.EntityPositionUpdate correction = ForceUpdate(
new Vector3(10f, 10f, SpawnHeight),
landblockId: deferredLandblock | 0x0001u);
(PositionTimestampDisposition disposition, AcceptedPhysicsTimestamps timestamps) =
MergeAccepted(runtime, controller, correction);
Assert.Equal(PositionTimestampDisposition.ForcePosition, disposition);
Assert.Equal(
RuntimeAcceptedPositionExecutionStatus.DeferredCell,
drive.TryExecuteAcceptedLocalPosition(
record,
correction,
disposition,
timestamps,
timestamps.PreviousTeleport));
// Measured, not assumed: this park happens AFTER
// `_physics.Engine.SetPosition` has already run, so the canonical body
// already sits at the destination while the placement itself is
// withdrawn and parked. Specifically it is the engine-result deferral
// (RuntimeSetPositionState.cs, the park taken once `operation.Result`
// has been assigned) — NOT either `TryGetBlockingQuiescence` branch:
// `_collisionPrefixQuiescence` is populated only by
// `BeginCollisionPrefixQuiescence`, and this fixture's
// `CommitLandblockCollision` calls `BeginCollisionGeneration` instead,
// so that map is empty and both quiescence branches are unreachable
// here. Same side of the engine call either way; the distinction only
// matters so a future reader does not go looking in the wrong branch.
// The subject of this test is the TERMINAL SETTLE, so the
// unmoved/no-further-placement baselines are captured here, at the park.
Vector3 poseAtPark = controller.Position;
ulong placementVersionAtPark = record.PlacementCommitVersion;
// Nothing has been acknowledged yet: retail's ack follows BlipPlayer,
// and the placement has not reached any terminal outcome.
Assert.Empty(gameActions);
// The park is retired without ever committing — the exact
// RuntimeSetPositionState.Forget funnel every mid-session cancellation
// shares (supersession, the lost-cell deadline, ParkCollisionResidents,
// a generation change).
RuntimePlacementCancellationReceipt cancellation =
runtime.EntityObjects.Physics.SetPosition.Forget(record);
if (cancellation.IsValid)
{
runtime.EntityObjects.Physics.SetPosition
.PublishCancellation(cancellation);
}
drive.Advance();
// Retail's two simultaneous facts at @0x0045409D: the placement did
// not take (the settle performs no placement of its own — the body is
// exactly where the retired operation left it and no further
// placement committed), and the position event went out anyway,
// carrying that unchanged pose. Before round 3 this path sent zero.
Assert.Equal(poseAtPark, controller.Position);
Assert.Equal(placementVersionAtPark, record.PlacementCommitVersion);
Assert.Single(gameActions);
Assert.Equal(0, drive.PendingCount);
// Retail never retries a force whose placement failed, so no further
// pump may place OR acknowledge anything more for this packet.
drive.Advance();
drive.Advance();
Assert.Single(gameActions);
Assert.Equal(poseAtPark, controller.Position);
Assert.Equal(placementVersionAtPark, record.PlacementCommitVersion);
AssertConverged(runtime);
}
/// <summary>
/// Round 3 companion invariant (2026-08-03): the terminal-without-commit
/// ack must not become a SECOND ack on the committed path. A commit runs
/// <c>ReconcileAndAcknowledge</c> and then immediately settles through the
/// same funnel, so a funnel that acknowledged unconditionally would send
/// two <c>AutonomousPosition</c> messages for one server correction — the
/// exact duplicate-ack class <c>670f307c</c> deleted. Retail sends exactly
/// one per handled packet (<c>SmartBox::HandleReceivedPosition</c>
/// @0x00453FD0 reaches <c>SendPositionEvent</c> @0x00454091 once, then
/// returns @0x0045409D).
/// </summary>
[Fact]
public void Committed_SendsExactlyOnePositionEventAcrossTheCommitAndTheSettle()
{
using StartedRuntime started = StartRuntime();
GameRuntime runtime = started.Runtime;
(RuntimeEntityRecord record, PlayerMovementController controller) =
EnterLocalPlayer(runtime);
RuntimeAcceptedPositionDriveController drive =
CreateAcceptedPositionDrive(runtime, out List<byte[]> gameActions);
// Within the already-published spawn landblock, so the placement
// commits synchronously AND the contact gate admits the ack.
var corrected = new Vector3(30f, 32f, SpawnHeight);
WorldSession.EntityPositionUpdate correction = ForceUpdate(corrected);
(PositionTimestampDisposition disposition, AcceptedPhysicsTimestamps timestamps) =
MergeAccepted(runtime, controller, correction);
Assert.Equal(PositionTimestampDisposition.ForcePosition, disposition);
Assert.Equal(
RuntimeAcceptedPositionExecutionStatus.Committed,
drive.TryExecuteAcceptedLocalPosition(
record,
correction,
disposition,
timestamps,
timestamps.PreviousTeleport));
// One commit, one ack — not two. The settle that runs immediately
// after the commit must recognise the ack already left.
Assert.Equal(corrected, controller.Position);
Assert.Single(gameActions);
Assert.Equal(0, drive.PendingCount);
drive.Advance();
drive.Advance();
Assert.Single(gameActions);
AssertConverged(runtime);
}
/// <summary>
/// C4 route 4b-2, round-3 correction A2 (test 1 of 2) — the LOCAL PLAYER
/// traverses the shared-core quiescence-park change, on the shape that is
/// actually reachable through this route.
///
/// <para>
/// <b>Reachability, measured rather than assumed.</b> The correction asked
/// for a park under a quiescing SOURCE, reached through
/// <c>PlacementTouchesPrefix</c>'s <c>CurrentCellId</c> arm. That shape is
/// not constructible: the merge this route requires
/// (<c>RuntimeEntityObjectLifetime.TryApplyPosition</c>) commits the
/// accepted wire cell to <c>record.FullCellId</c> BEFORE the drive is
/// called, and <c>CurrentCellId</c> is read from that field — so by submit
/// time it names the DESTINATION, not the landblock being left. The
/// reachable pre-sweep shape is therefore a quiescing destination; the
/// reachable post-sweep shape is a quiescing swept neighbour, which is the
/// sibling test below.
/// </para>
///
/// <para>
/// A quiescing destination is the one shape where the rollback genuinely
/// would re-admit a spatial root into the prefix that is trying to
/// quiesce, so <c>ParkDeferred</c> declines it — AP-136's stated reason,
/// applied to the cell the restore would actually use. Route 2 has no
/// destination pre-flight of its own (unlike the remote far arm's
/// <c>CanAttemptDestination</c>), so it reaches this unmasked.
/// </para>
/// </summary>
[Fact]
public void QuiescingDestinationPrefix_ForcePositionParkIsNotRestored()
{
using StartedRuntime started = StartRuntime();
GameRuntime runtime = started.Runtime;
(RuntimeEntityRecord record, PlayerMovementController controller) =
EnterLocalPlayer(runtime);
PhysicsBody body = Assert.IsType<PhysicsBody>(record.PhysicsBody);
RuntimeAcceptedPositionDriveController drive =
CreateAcceptedPositionDrive(runtime, out _);
runtime.EntityObjects.Physics.SetPosition.BeginCollisionPrefixQuiescence(
DestinationLandblock,
collisionGeneration: 2UL,
includeOutdoorCells: true);
WorldSession.EntityPositionUpdate correction = ForceUpdate(
new Vector3(10f, 10f, SpawnHeight),
landblockId: DestinationLandblock | 0x0001u);
(PositionTimestampDisposition disposition, AcceptedPhysicsTimestamps timestamps) =
MergeAccepted(runtime, controller, correction);
Assert.Equal(PositionTimestampDisposition.ForcePosition, disposition);
Assert.Equal(
RuntimeAcceptedPositionExecutionStatus.DeferredCell,
drive.TryExecuteAcceptedLocalPosition(
record,
correction,
disposition,
timestamps,
timestamps.PreviousTeleport));
Assert.False(body.InWorld);
// ACE's next ordinary broadcast, ~100-200 ms later. Its merge-time
// Forget cancels the park — and the rollback must decline, because the
// only cell it could restore into is the retiring one.
MergeAccepted(
runtime,
controller,
OrdinaryUpdate(new Vector3(31f, 33f, SpawnHeight), positionSequence: 3));
Assert.False(runtime.EntityObjects.Physics.IsSpatialRoot(record));
Assert.False(body.InWorld);
Assert.False(record.ObjectClock.IsActive);
drive.Advance();
Assert.Equal(0, drive.PendingCount);
AssertConverged(runtime);
}
/// <summary>
/// C4 route 4b-2, round-3 correction A2 (test 2 of 2) — the reachable
/// RESTORABLE quiescence park on the local-player route.
///
/// <para>
/// The correction is placed one sphere radius inside the seam between
/// <see cref="SpawnLandblock"/> and its +X neighbour, so
/// <c>CellTransit.AddAllOutsideCells</c> adds the neighbour's cells to the
/// sweep footprint (<c>AddOutsideCell</c> re-derives the block id from the
/// global lcoord and has no same-block filter). Core's
/// <c>ResultTouchesPrefix</c> scans every <c>QueriedCellIds</c> entry, so
/// a healthy, resident, about-to-COMMIT ForcePosition is rewritten to
/// <c>DeferredCell</c> by a quiescence in a landblock the player is
/// neither in nor going to.
/// </para>
///
/// <para>
/// Before the shared-core change every quiescence park was non-restorable,
/// so the next packet's merge-time <c>Forget</c> destroyed the only
/// operation able to wake the player and left it <c>InWorld = false</c>,
/// clock suspended, not a spatial root — session-permanent, because
/// nothing else restores that state. The three asserts at the end are that
/// defect. Restoring is safe here for the reason
/// <c>ParkDeferred</c> tests directly: the cell it would restore into is
/// the destination, and the destination is not quiescing.
/// </para>
/// </summary>
[Fact]
public void QuiescingSweptNeighbour_ForcePositionParkIsRestoredByTheNextPacket()
{
using StartedRuntime started = StartRuntime();
GameRuntime runtime = started.Runtime;
(RuntimeEntityRecord record, PlayerMovementController controller) =
EnterLocalPlayer(runtime);
CommitLandblockCollision(
runtime, NeighbourLandblock, worldOffsetX: 192f);
PhysicsBody body = Assert.IsType<PhysicsBody>(record.PhysicsBody);
RuntimeAcceptedPositionDriveController drive =
CreateAcceptedPositionDrive(runtime, out _);
runtime.EntityObjects.Physics.SetPosition.BeginCollisionPrefixQuiescence(
NeighbourLandblock,
collisionGeneration: 2UL,
includeOutdoorCells: true);
// Neither the source nor the destination is quiescing — the whole
// point of the shape.
Assert.False(
runtime.EntityObjects.Physics.SetPosition.IsCollisionPrefixQuiescing(
SpawnLandblock));
// Block-local X = 191.95 m: inside cell (7, 0), 0.05 m from the 192 m
// seam, well inside the local player's own sphere radius, which is the
// `pointX > CellLength - radius` test AddAllOutsideCells applies
// before adding lx + 1.
WorldSession.EntityPositionUpdate correction = ForceUpdate(
new Vector3(191.95f, 10f, SpawnHeight),
landblockId: SpawnSeamCell);
(PositionTimestampDisposition disposition, AcceptedPhysicsTimestamps timestamps) =
MergeAccepted(runtime, controller, correction);
Assert.Equal(PositionTimestampDisposition.ForcePosition, disposition);
Assert.Equal(
RuntimeAcceptedPositionExecutionStatus.DeferredCell,
drive.TryExecuteAcceptedLocalPosition(
record,
correction,
disposition,
timestamps,
timestamps.PreviousTeleport));
Assert.False(body.InWorld);
MergeAccepted(
runtime,
controller,
OrdinaryUpdate(new Vector3(31f, 33f, SpawnHeight), positionSequence: 3));
Assert.True(body.InWorld);
Assert.True(record.ObjectClock.IsActive);
Assert.True(runtime.EntityObjects.Physics.IsSpatialRoot(record));
drive.Advance();
Assert.Equal(0, drive.PendingCount);
AssertConverged(runtime);
}
/// <summary>
/// C4 route 4b-2, round-4 correction (the MAJOR) — the DISCRIMINATING
/// test. Round 3 relocated the restorable-park decision out of the two
/// <c>SubmitPreparedPlacementCore</c> call sites and into
/// <c>ParkDeferred</c>, but nothing in the tree distinguished the new
/// predicate from the one it replaced. This does.
///
/// <para>
/// <b>Round 2's form</b> compared the blocking quiescence's own token
/// against the caller's pre-snap cell:
/// <c>blockingToken.LandblockPrefix != (result.CellId &amp; 0xFFFF0000)</c>.
/// <b>Round 3's form</b> tests the POST-snap cell against every live
/// quiescence: <c>!IsCollisionPrefixQuiescing(body.CellPosition.ObjCellId)</c>.
/// Under round 2 this test's player is left withdrawn — <c>InWorld</c>
/// false, clock suspended, not a spatial root — for the rest of the
/// session. That is the exact stranding AP-136's rollback exists to
/// prevent, and it is reached without a second quiescence, purely because
/// the two forms read different cells.
/// </para>
///
/// <para>
/// <b>The shape.</b> The server names a cell in the player's OWN
/// landblock but supplies a block-local X 5 cm PAST that block's 192 m
/// seam. A wire (cell, position) pair that disagrees is exactly the pair
/// <c>PhysicsBody.StageDormantCellFrame</c>'s
/// <c>LandDefs.AdjustToOutside</c> exists to distrust (#107: "never trust
/// a server (cell, pos) pair without re-deriving the cell"), and
/// <c>AdjustToOutside</c>'s own contract says the re-derived id may
/// belong to a NEIGHBOUR landblock — which is what happens here. So the
/// prefix the placement PARKED against (the player's own, mid-retirement)
/// and the prefix residency would be RESTORED into (the healthy
/// neighbour) are different landblocks, and only the second one is the
/// question <c>RestoreParkWithdrawal</c> actually asks.
/// </para>
///
/// <para>
/// Route 2 is the home for it because it has no destination pre-flight:
/// the remote far arm's <c>CanAttemptDestination</c> refuses a quiescing
/// destination before any park is opened, so this park is unreachable
/// there.
/// </para>
/// </summary>
[Fact]
public void QuiescingOwnPrefix_SeamCrossingParkIsRestoredAtTheReDerivedNeighbourCell()
{
using StartedRuntime started = StartRuntime();
GameRuntime runtime = started.Runtime;
(RuntimeEntityRecord record, PlayerMovementController controller) =
EnterLocalPlayer(runtime);
PhysicsBody body = Assert.IsType<PhysicsBody>(record.PhysicsBody);
RuntimeAcceptedPositionDriveController drive =
CreateAcceptedPositionDrive(runtime, out _);
// Streaming begins retiring/republishing the player's OWN landblock,
// which is also the landblock the wire cell names.
runtime.EntityObjects.Physics.SetPosition.BeginCollisionPrefixQuiescence(
SpawnLandblock,
collisionGeneration: 2UL,
includeOutdoorCells: true);
// Cell (7, 0) of SpawnLandblock covers block-local X in [168, 192).
// 192.05 m is 5 cm past its block's own seam, so AdjustToOutside
// re-derives lx = 8 + floor(192.05 / 24) = 16, i.e. block X index 2,
// and LcoordToGid rebuilds the id as NeighbourLandblock | 1.
WorldSession.EntityPositionUpdate correction = ForceUpdate(
new Vector3(192.05f, 10f, SpawnHeight),
landblockId: SpawnSeamCell);
(PositionTimestampDisposition disposition, AcceptedPhysicsTimestamps timestamps) =
MergeAccepted(runtime, controller, correction);
Assert.Equal(PositionTimestampDisposition.ForcePosition, disposition);
Assert.Equal(
RuntimeAcceptedPositionExecutionStatus.DeferredCell,
drive.TryExecuteAcceptedLocalPosition(
record,
correction,
disposition,
timestamps,
timestamps.PreviousTeleport));
Assert.False(body.InWorld);
// The two cells the two predicate forms read are DIFFERENT
// landblocks, and only the quiescing one is the caller's.
Assert.Equal(SpawnLandblock, correction.Position.LandblockId & 0xFFFF0000u);
Assert.Equal(
NeighbourLandblock,
body.CellPosition.ObjCellId & 0xFFFF0000u);
Assert.False(
runtime.EntityObjects.Physics.SetPosition.IsCollisionPrefixQuiescing(
NeighbourLandblock));
// ACE's next ordinary broadcast cancels the park at merge time.
MergeAccepted(
runtime,
controller,
OrdinaryUpdate(new Vector3(31f, 33f, SpawnHeight), positionSequence: 3));
// Restored, because the cell residency is restored INTO is healthy.
// All three of these fail under round 2's single-token form.
Assert.True(body.InWorld);
Assert.True(record.ObjectClock.IsActive);
Assert.True(runtime.EntityObjects.Physics.IsSpatialRoot(record));
drive.Advance();
Assert.Equal(0, drive.PendingCount);
AssertConverged(runtime);
}
/// <summary>
/// C4 route 4b-2, round-4 correction D6 — the restorable decision is
/// re-tested at RESTORE time, not only at park time.
///
/// <para>
/// <c>ParkDeferred</c>'s decision is a snapshot. The far snap cancels its
/// park synchronously, so that snapshot cannot go stale; route 2's park is
/// RETAINED (<c>AwaitingCommitWake</c>) and the restore lands on the next
/// packet's merge-time <c>Forget</c>, ~150 ms later at ACE's 5-10 Hz.
/// Streaming opens a quiescence per landblock mutation, so the cell the
/// rollback would restore into can start quiescing inside that window.
/// </para>
///
/// <para>
/// This drives exactly that: a swept-NEIGHBOUR quiescence parks a
/// placement whose destination is healthy (so the park IS restorable when
/// taken), then the destination's own prefix begins quiescing before the
/// next packet. The restore must decline — otherwise it re-admits a
/// spatial root into a prefix that is trying to retire, which is AP-136's
/// stated reason verbatim. The entity self-heals on a later packet, so
/// declining here is strictly the conservative half.
/// </para>
/// </summary>
[Fact]
public void QuiescenceOpenedAfterTheParkDeclinesTheRestoreAtMergeTime()
{
using StartedRuntime started = StartRuntime();
GameRuntime runtime = started.Runtime;
(RuntimeEntityRecord record, PlayerMovementController controller) =
EnterLocalPlayer(runtime);
CommitLandblockCollision(
runtime, NeighbourLandblock, worldOffsetX: 192f);
PhysicsBody body = Assert.IsType<PhysicsBody>(record.PhysicsBody);
RuntimeAcceptedPositionDriveController drive =
CreateAcceptedPositionDrive(runtime, out _);
runtime.EntityObjects.Physics.SetPosition.BeginCollisionPrefixQuiescence(
NeighbourLandblock,
collisionGeneration: 2UL,
includeOutdoorCells: true);
WorldSession.EntityPositionUpdate correction = ForceUpdate(
new Vector3(191.95f, 10f, SpawnHeight),
landblockId: SpawnSeamCell);
(PositionTimestampDisposition disposition, AcceptedPhysicsTimestamps timestamps) =
MergeAccepted(runtime, controller, correction);
Assert.Equal(PositionTimestampDisposition.ForcePosition, disposition);
Assert.Equal(
RuntimeAcceptedPositionExecutionStatus.DeferredCell,
drive.TryExecuteAcceptedLocalPosition(
record,
correction,
disposition,
timestamps,
timestamps.PreviousTeleport));
Assert.False(body.InWorld);
// The park WAS restorable when it was taken: the destination prefix
// was clean. (Its sibling test above asserts the restore that follows
// from exactly this state.)
Assert.Equal(
SpawnLandblock,
body.CellPosition.ObjCellId & 0xFFFF0000u);
// …and now streaming retires that very landblock, mid-park.
runtime.EntityObjects.Physics.SetPosition.BeginCollisionPrefixQuiescence(
SpawnLandblock,
collisionGeneration: 3UL,
includeOutdoorCells: true);
MergeAccepted(
runtime,
controller,
OrdinaryUpdate(new Vector3(31f, 33f, SpawnHeight), positionSequence: 3));
Assert.False(runtime.EntityObjects.Physics.IsSpatialRoot(record));
drive.Advance();
Assert.Equal(0, drive.PendingCount);
AssertConverged(runtime);
}
private static void AssertConverged(GameRuntime runtime)
{
RuntimeEntityObjectOwnershipSnapshot ownership =
runtime.EntityObjects.CaptureOwnership();
Assert.Equal(0, ownership.AcceptedPositionDrivePendingCount);
}
/// <summary>
/// Performs the SAME upstream merge production runs BEFORE this route
/// ever sees a Position
/// (<see cref="RuntimeEntityObjectLifetime.TryApplyPosition"/>, called by
/// <c>LiveEntityInboundAuthorityGate.TryAcceptPosition</c> in App and
/// directly in <c>RuntimeLiveEntitySessionController.OnPositionUpdated</c>
/// in headless) — this is what actually admits the disposition via the
/// REAL <c>PhysicsTimestampGate</c> and substitutes the controller's
/// current heading into <c>record.Snapshot</c> for a ForcePosition
/// (contract §1c), rather than hand-rolling a disposition/timestamps pair
/// the seam's caller could never actually observe.
/// </summary>
private static (PositionTimestampDisposition Disposition, AcceptedPhysicsTimestamps Timestamps)
MergeAccepted(
GameRuntime runtime,
PlayerMovementController controller,
in WorldSession.EntityPositionUpdate update)
{
Assert.True(runtime.EntityObjects.TryApplyPosition(
update,
isLocalPlayer: true,
forcePositionRotation: controller.BodyOrientation,
currentLocalVelocity: controller.BodyVelocity,
projectionRequiresTeleportHook: false,
acknowledgeProjection: null,
out PositionTimestampDisposition disposition,
out _,
out AcceptedPhysicsTimestamps timestamps));
return (disposition, timestamps);
}
/// <summary>
/// A wire Position whose FORCE_POSITION_TS strictly advances, so the REAL
/// <see cref="PhysicsTimestampGate.TryAcceptPositionEvent"/> admits it as
/// <see cref="PositionTimestampDisposition.ForcePosition"/> (retail
/// <c>SmartBox::HandleReceivedPosition</c> @0x00453FD0's FORCE_POSITION
/// branch: fresh FORCE_POSITION_TS with an exactly-equal TELEPORT_TS).
/// The spawn seeds FORCE_POSITION_TS 0 / POSITION_TS 1, so the defaults
/// are the FIRST such packet; a session's SECOND force must raise
/// <paramref name="forcePositionSequence"/> again.
/// </summary>
private static WorldSession.EntityPositionUpdate ForceUpdate(
Vector3 position,
uint landblockId = SpawnLandblock | 0x0001u,
ushort positionSequence = 2,
ushort forcePositionSequence = 1) =>
new(
PlayerGuid,
new CreateObject.ServerPosition(
landblockId,
position.X,
position.Y,
position.Z,
1f,
0f,
0f,
0f),
Velocity: null,
PlacementId: null,
IsGrounded: true,
InstanceSequence: 1,
PositionSequence: positionSequence,
TeleportSequence: 0,
ForcePositionSequence: forcePositionSequence);
/// <summary>
/// An ORDINARY server position echo: FORCE_POSITION_TS does NOT advance,
/// POSITION_TS strictly does, so the same real gate admits it as
/// <see cref="PositionTimestampDisposition.Apply"/>. Neither host ever
/// dispatches this disposition to the drive — it merges (advancing
/// <c>PositionAuthorityVersion</c> and Forgetting any in-flight placement)
/// entirely behind the drive's back, which is exactly what makes it the
/// N2 case.
/// </summary>
private static WorldSession.EntityPositionUpdate OrdinaryUpdate(
Vector3 position,
ushort positionSequence,
ushort forcePositionSequence = 1,
uint landblockId = SpawnLandblock | 0x0001u) =>
ForceUpdate(
position,
landblockId,
positionSequence,
forcePositionSequence);
private static AcceptedPhysicsTimestamps Timestamps(ushort teleport) =>
new(
Instance: 1,
ServerControlledMove: 1,
Teleport: teleport,
ForcePosition: 1,
TeleportAdvanced: false,
TeleportHookRequired: false,
PreviousTeleport: teleport);
/// <summary>
/// Spawns the local player, drives its initial-Create residence to
/// completion, and returns the resulting canonical record + live
/// controller — the fixture every test above needs before a
/// ForcePosition can be route-2-eligible at all.
/// </summary>
private static (RuntimeEntityRecord Record, PlayerMovementController Controller)
EnterLocalPlayer(GameRuntime runtime)
{
runtime.PlayerIdentity.ServerGuid = PlayerGuid;
CommitLandblockCollision(runtime, SpawnLandblock);
RuntimeFirstEntryDriveController firstEntry = CreateFirstEntryDrive(runtime);
using var session = new WorldSession(
new IPEndPoint(IPAddress.Loopback, 9000),
new FixtureTransport());
var sessionController = new RuntimeLiveEntitySessionController(
runtime,
session,
worldProjection: new FixtureWorldProjection(firstEntry));
LiveEntitySessionSink sink = sessionController.CreateSink();
sink.Spawned(Spawn(PlayerGuid));
DrainFirstEntry(runtime, firstEntry);
RuntimeEntityRecord record = Assert.IsType<RuntimeEntityRecord>(
GetActive(runtime, PlayerGuid));
PlayerMovementController controller = Assert.IsType<PlayerMovementController>(
runtime.MovementOwner.Controller);
return (record, controller);
}
private static RuntimeEntityRecord GetActive(GameRuntime runtime, uint guid)
{
Assert.True(runtime.EntityObjects.Entities.TryGetActive(
guid, out RuntimeEntityRecord record));
return record;
}
/// <summary>
/// Constructs the drive controller with a LIVE (deliberately never
/// disposed within this factory — it must outlive the whole test)
/// fixture <see cref="WorldSession"/> whose captured outbound game
/// actions the caller can assert against.
/// </summary>
private static RuntimeAcceptedPositionDriveController CreateAcceptedPositionDrive(
GameRuntime runtime,
out List<byte[]> gameActions)
{
var captured = new List<byte[]>();
gameActions = captured;
var liveSession = new WorldSession(
new IPEndPoint(IPAddress.Loopback, 9001),
new FixtureTransport())
{
GameActionCapture = body => captured.Add(body),
};
return new RuntimeAcceptedPositionDriveController(
runtime.EntityObjects,
runtime.Clock,
new UnusedCollisionSource(),
new LocalPlayerOutboundController((_, _, _, _, _, _) => { }),
() => runtime.Generation,
() => runtime.PlayerIdentity.ServerGuid,
() => runtime.MovementOwner.Controller,
() => runtime.CharacterOwner.UsePositionFromServer,
() => liveSession);
}
/// <summary>
/// A flat landblock whose terrain surface sits exactly at
/// <see cref="SpawnHeight"/> — every fixture position in this file uses
/// that Z so <c>CommitCanonical</c>'s contact resolve genuinely finds
/// ground (retail <c>CommandInterpreter::SendPositionEvent</c>'s own
/// admission gate requires Contact+OnWalkable —
/// <c>PlayerMovementController.CanSendPositionEvent</c> — so an airborne
/// fixture body would silently suppress every ack this suite asserts).
/// </summary>
private static void CommitLandblockCollision(
GameRuntime runtime,
uint landblockId,
float worldOffsetX = 0f)
{
// Mirrors HeadlessSessionHostTests.AddFlatLandblock's exact
// proven-working shape (every heightmap byte and every table entry
// participate) rather than a sparse table — a resolve near a
// landblock edge samples neighbouring grid entries too.
var heights = new byte[81];
Array.Fill(heights, (byte)SpawnHeight);
var heightTable = new float[256];
for (int index = 0; index < heightTable.Length; index++)
heightTable[index] = index;
runtime.EntityObjects.Physics.SetPosition.BeginCollisionGeneration(
landblockId, 1UL);
runtime.EntityObjects.Physics.Engine.AddLandblock(
landblockId,
new TerrainSurface(heights, heightTable),
Array.Empty<CellSurface>(),
Array.Empty<PortalPlane>(),
worldOffsetX,
worldOffsetY: 0f);
runtime.EntityObjects.Physics.SetPosition.CommitCollisionGeneration(
landblockId, 1UL, ready: true);
runtime.EntityObjects.Physics.ObserveLocalWorldFrame(
landblockId | 0x0001u,
teleportAdvanced: false);
}
private static RuntimeFirstEntryDriveController CreateFirstEntryDrive(
GameRuntime runtime) =>
new(
runtime.EntityObjects,
runtime.Clock,
new UnusedCollisionSource(),
() => PlayerMovementConstructionOptions.Fallback,
static _ => new RuntimeLocalPlayerPhysicsActivationPreparation(
Radius: 0.48f,
Height: 1.835f,
RuntimeLocalPlayerShadowDisposition.ProvenShapeless));
private static void DrainFirstEntry(
GameRuntime runtime,
RuntimeFirstEntryDriveController drive)
{
for (int attempt = 0; attempt < 8 && drive.PendingCount != 0; attempt++)
{
drive.DriveAll();
DrainPlacementFifo(runtime);
}
Assert.Equal(0, drive.PendingCount);
}
private static void DrainPlacementFifo(GameRuntime runtime)
{
while (runtime.EntityObjects.Physics.SetPosition.TryPeekProjection(
out RuntimePlacementProjectionSnapshot head))
{
if (!runtime.EntityObjects.Physics.SetPosition
.AcknowledgeProjection(head.Token))
{
break;
}
}
}
private static WorldSession.EntitySpawn Spawn(uint guid)
{
var position = new CreateObject.ServerPosition(
SpawnLandblock | 0x0001u,
10f,
10f,
5f,
1f,
0f,
0f,
0f);
var timestamps = new PhysicsTimestamps(
Position: 1,
Movement: 1,
State: 1,
Vector: 1,
Teleport: 0,
ServerControlledMove: 1,
ForcePosition: 0,
ObjDesc: 1,
Instance: 1);
var physics = new PhysicsSpawnData(
RawState: (uint)PhysicsStateFlags.ReportCollisions,
Position: position,
Movement: null,
AnimationFrame: null,
SetupTableId: null,
MotionTableId: null,
SoundTableId: null,
PhysicsScriptTableId: null,
Parent: null,
Children: null,
Scale: null,
Friction: null,
Elasticity: null,
Translucency: null,
Velocity: null,
Acceleration: null,
AngularVelocity: null,
DefaultScriptType: null,
DefaultScriptIntensity: null,
Timestamps: timestamps);
return new WorldSession.EntitySpawn(
guid,
position,
null,
[],
[],
[],
null,
null,
"direct entity",
null,
null,
null,
PhysicsState: physics.RawState,
InstanceSequence: 1,
MovementSequence: 1,
ServerControlSequence: 1,
PositionSequence: 1,
Physics: physics);
}
private sealed class UnusedCollisionSource
: AcDream.Content.IPreparedCollisionSource
{
public AcDream.Content.PreparedAssetPresence ProbeCollision(
AcDream.Content.Pak.PakAssetType type,
uint sourceFileId) =>
AcDream.Content.PreparedAssetPresence.Available;
public AcDream.Content.PreparedCollisionReadResult<
FlatSetupCollision> ReadSetupCollision(
uint sourceFileId,
CancellationToken cancellationToken = default) =>
AcDream.Content.PreparedCollisionReadResult<
FlatSetupCollision>.Missing;
public AcDream.Content.PreparedCollisionReadResult<
FlatGfxObjCollisionAsset> ReadGfxObjCollision(
uint sourceFileId,
CancellationToken cancellationToken = default) =>
throw new NotSupportedException();
public AcDream.Content.PreparedCollisionReadResult<
FlatCellStructureCollisionAsset> ReadCellStructureCollision(
uint sourceFileId,
CancellationToken cancellationToken = default) =>
throw new NotSupportedException();
public AcDream.Content.PreparedCollisionReadResult<
FlatEnvCellTopology> ReadEnvCellTopology(
uint sourceFileId,
CancellationToken cancellationToken = default) =>
throw new NotSupportedException();
public AcDream.Content.PreparedCollisionSourceStats CollisionStats =>
default;
public void Dispose()
{
}
}
private sealed class FixtureTransport : IWorldSessionTransport
{
public void Send(ReadOnlySpan<byte> datagram)
{
}
public void Send(
IPEndPoint remote,
ReadOnlySpan<byte> datagram)
{
}
public int Receive(
Span<byte> destination,
TimeSpan timeout,
out IPEndPoint? from)
{
from = null;
return -1;
}
public ValueTask<NetReceiveResult> ReceiveAsync(
Memory<byte> destination,
CancellationToken cancellationToken) =>
ValueTask.FromException<NetReceiveResult>(
new OperationCanceledException(cancellationToken));
public void Dispose()
{
}
}
private sealed class FixtureWorldProjection : IRuntimeDirectWorldProjection
{
private readonly RuntimeFirstEntryDriveController _firstEntry;
internal FixtureWorldProjection(RuntimeFirstEntryDriveController firstEntry) =>
_firstEntry = firstEntry;
public void ProjectSpawn(RuntimeEntityRecord record, bool isLocalPlayer) =>
_firstEntry.DriveAll();
public void ProjectPosition(
RuntimeEntityRecord record,
bool isLocalPlayer,
PositionTimestampDisposition disposition)
{
}
public void CenterOnAcceptedForcePosition(RuntimeEntityRecord record)
{
}
public void BeginTeleport()
{
}
public RuntimeDestinationReadiness PrepareDestination(
long revealGeneration,
RuntimeTeleportDestination destination) =>
new(
revealGeneration,
destination.CellId,
IsIndoor: false,
IsUnhydratable: false,
RequiredRenderRadius: 1,
IsRenderNeighborhoodReady: true,
AreCompositeTexturesReady: true,
IsCollisionReady: true);
}
/// <summary>
/// C3c: initial-residence admission requires a live session generation
/// (RuntimeInitialCreateResidenceState.CanAcceptCreate), so this test
/// starts one through the same fixture-session shape
/// DirectGameRuntimeCommandAdapterTests / RuntimeLiveEntitySessionControllerTests use.
/// </summary>
private sealed class StartedRuntime : IDisposable
{
internal required GameRuntime Runtime { get; init; }
internal required LiveSessionHost Live { get; init; }
public void Dispose()
{
_ = Live.Stop(Runtime.Generation);
Runtime.Dispose();
}
}
private static StartedRuntime StartRuntime()
{
var operations = new FixtureGameplayOperations();
var sessionOperations = new FixtureSessionOperations();
var runtime = new GameRuntime(new GameRuntimeDependencies(
operations,
operations,
operations,
operations,
SessionOperations: sessionOperations));
operations.Bind(runtime);
var resetHost = new FixtureResetHost();
var options = new LiveSessionConnectOptions(
true,
"127.0.0.1",
9000,
"account",
"password");
var live = new LiveSessionHost(
runtime.Session,
new LiveSessionHostBindings(
new LiveSessionRoutingFactories(
_ => new FixtureEventRoute(),
_ => new FixtureCommandRoute()),
generation => runtime.ResetGeneration(generation, resetHost),
new LiveSessionSelectionBindings(
id => runtime.PlayerIdentity.ServerGuid = id,
_ => { },
runtime.CommunicationOwner.Chat.SetLocalPlayerGuid,
_ => { },
_ => { },
runtime.ActionOwner.Combat.Clear),
new LiveSessionEnteredWorldBindings(
_ => { },
() => { },
() => { },
_ => { },
() => { }),
(_, _, _) => { },
() => { }),
options);
LiveSessionStartResult startResult = live.Start(options);
Assert.Equal(LiveSessionStartStatus.Connected, startResult.Status);
Assert.NotEqual(0UL, runtime.Generation.Value);
return new StartedRuntime { Runtime = runtime, Live = live };
}
private sealed class FixtureSessionOperations : ILiveSessionOperations
{
public IPEndPoint ResolveEndpoint(string host, int port) =>
new(IPAddress.Loopback, port);
public WorldSession CreateSession(IPEndPoint endpoint) =>
new(endpoint, new FixtureTransport());
public void Connect(WorldSession session, string user, string password)
{
}
public CharacterList.Parsed GetCharacters(WorldSession session) =>
new(
0u,
[new CharacterList.Character(PlayerGuid, "Direct", 0u)],
[],
11,
"account",
true,
true);
public void EnterWorld(WorldSession session, int activeCharacterIndex)
{
}
public void Tick(WorldSession session)
{
}
public void DisposeSession(WorldSession session) =>
session.Dispose();
}
private sealed class FixtureEventRoute : ILiveSessionEventRouting
{
public void Attach()
{
}
public void Dispose()
{
}
}
private sealed class FixtureCommandRoute : ILiveSessionCommandRouting
{
public void Activate()
{
}
public void Dispose()
{
}
}
private sealed class FixtureResetHost : IRuntimeGenerationResetHost
{
public void RetireEntityProjection(RuntimeEntityRecord entity)
{
}
public void DrainEntityProjectionBoundary()
{
}
public void CompleteEntityProjectionRetirement()
{
}
}
private sealed class FixtureGameplayOperations
: IRuntimeCombatAttackOperations,
IRuntimeCombatTargetOperations,
IRuntimeCombatModeOperations,
IRuntimeSpellCastOperations
{
private GameRuntime? _runtime;
public void Bind(GameRuntime runtime) => _runtime = runtime;
public bool CanStartAttack() => false;
public void PrepareAttackRequest()
{
}
public bool SendAttack(AttackHeight height, float power) => false;
public void SendCancelAttack()
{
}
public bool IsDualWield => false;
public bool PlayerReadyForAttack => false;
public bool AutoRepeatAttack => false;
public bool AutoTarget => false;
public uint? SelectClosestTarget() => null;
public bool IsInWorld => _runtime?.Session.IsInWorld == true;
public IReadOnlyList<ClientObject> GetOrderedEquipment() => [];
public void NotifyExplicitCombatModeRequest()
{
}
public void SendChangeCombatMode(CombatMode mode)
{
}
public uint LocalPlayerId =>
_runtime?.PlayerIdentity.ServerGuid ?? 0u;
public bool CanSend => false;
public bool HasRequiredComponents(uint spellId) => false;
public bool IsTargetCompatible(
uint targetId,
SpellMetadata spell,
bool showMessage) => false;
public void StopCompletely()
{
}
public void SendUntargeted(uint spellId)
{
}
public void SendTargeted(uint targetId, uint spellId)
{
}
public void DisplayMessage(string message)
{
}
public void IncrementBusy()
{
}
}
}