using System.Net;
using System.Numerics;
using AcDream.App.Input;
using AcDream.App.Physics;
using AcDream.App.Rendering;
using AcDream.App.Rendering.Vfx;
using AcDream.App.Streaming;
using AcDream.App.World;
using AcDream.Content;
using AcDream.Content.Pak;
using AcDream.Core.Items;
using AcDream.Core.Net;
using AcDream.Core.Net.Messages;
using AcDream.Core.Physics;
using AcDream.Core.Plugins;
using AcDream.Core.World;
using AcDream.Runtime;
using AcDream.Runtime.Entities;
using AcDream.Runtime.Gameplay;
using AcDream.Runtime.Physics;
using AcDream.Runtime.Session;
using AcDream.Runtime.World;
using DatReaderWriter.DBObjs;
namespace AcDream.App.Tests.World;
///
/// C5a §5.2 (2026-08-05) — the route-2 B2 closure, corrected at the
/// architecture-review re-pass (A3). Route 2's review
/// (docs/research/2026-08-03-c4-route-2-review-findings.md B2) found:
/// "no test drives a route-2 ForcePosition through
/// /
/// LiveEntityRuntime.TryApplyRuntimePlacementPlace and asserts the
/// moved."
///
///
/// A3 correction: the first version of this test hand-authored a
/// RuntimePlacementProjectionSnapshot and called Sink.TryApply
/// directly — it never drove a ForcePosition at all, and the five facts it
/// asserted were already pinned by
/// RuntimePlacementPresentationSinkTests.Place_ReframesAndRebucketsExactSidecarWithoutMutatingRuntimePhysics.
/// This version drives the REAL production path: a bare
/// hosts a live local player
/// ( → the real
///
/// pump, mirroring RuntimeFirstEntryHostIntegrationTests's established
/// composition), then a REAL
///
/// call — fed by the REAL
/// merge, exactly like RuntimeAcceptedPositionDriveControllerTests.MergeAccepted
/// — commits the canonical placement. The REAL
///
/// (subscribed to the SAME 's
/// placement channel) synchronously forwards the resulting receipt to the
/// REAL , which writes the
/// render . Nothing in this chain is hand-authored;
/// the receipt is the ForcePosition path's OWN output.
///
///
///
/// Sabotage-verified (manual): with the receipt→render write severed
/// (RuntimePlacementPresentationSink.TryApply short-circuited to
/// acknowledge-and-ignore a Place without calling
/// LiveEntityRuntime.TryApplyRuntimePlacementProjection), the test
/// fails at exactly the position assertion (the entity stays at its
/// pre-force pose); restored, it is green.
///
///
public sealed class RuntimeForcePositionRenderCommitTests
{
private const uint Cell = 0x01010001u;
private const uint PlayerGuid = 0x7000B201u;
// M1 (architecture review round 2, 2026-08-05): landblock-local (30,30)
// deliberately crosses OUT of the spawn's outdoor grid cell (cx=0,cy=0 ->
// low word 0x0001) into cx=1,cy=1 (TerrainSurface.CellSize=24) -> low
// word 0x000A, so ForcedCell != Cell and the cell assertion below is
// actually falsifiable. The prior (15,15) choice stayed inside the SAME
// grid cell as the spawn, so Assert.Equal(Cell, entity.ParentCellId)
// passed before the drive ever ran — a vacuous cell assertion the
// position assertion's own strength (wire Z=0 vs resolved Z=0.48) had
// been masking.
private static readonly Vector3 ForcedPosition = new(30f, 30f, 0.48f);
private const uint ForcedCell = 0x0101000Au;
[Fact]
public void AcceptedForcePosition_DrivenEndToEnd_MovesRenderEntityFromTheCommittedReceipt()
{
using var fixture = new HostFixture();
fixture.Controller.OnCreate(Spawn(PlayerGuid, Cell));
PlayerMovementController controller = Assert.IsType(
fixture.Movement.Controller);
Assert.True(fixture.Runtime.TryGetRecord(PlayerGuid, out LiveEntityRecord record));
WorldEntity entity = Assert.IsType(record.WorldEntity);
Vector3 positionBeforeForce = entity.Position;
// The accepted ForcePosition wire update — a genuine forced position
// and heading correction, admitted by the REAL PhysicsTimestampGate
// (fresh FORCE_POSITION_TS with an equal TELEPORT_TS, retail
// SmartBox::HandleReceivedPosition @0x00453FD0's FORCE_POSITION
// branch) exactly like RuntimeAcceptedPositionDriveControllerTests
// drives it in Runtime.Tests.
WorldSession.EntityPositionUpdate wire = ForceUpdate(ForcedPosition);
Assert.True(fixture.EntityObjects.TryApplyPosition(
wire,
isLocalPlayer: true,
forcePositionRotation: controller.BodyOrientation,
currentLocalVelocity: controller.BodyVelocity,
acknowledgeProjection: null,
out PositionTimestampDisposition disposition,
out _,
out AcceptedPhysicsTimestamps timestamps));
Assert.Equal(PositionTimestampDisposition.ForcePosition, disposition);
RuntimeAcceptedPositionExecutionStatus status =
fixture.Drive.TryExecuteAcceptedLocalPosition(
record.Canonical,
wire,
disposition,
timestamps,
timestamps.PreviousTeleport);
// THE DISCRIMINATING ASSERTIONS. Nothing here is asserted from the
// wire update or a hand-authored snapshot — every value is read back
// from the render entity AFTER the real drive + real subscription +
// real sink chain ran.
Assert.Equal(RuntimeAcceptedPositionExecutionStatus.Committed, status);
Assert.NotEqual(positionBeforeForce, entity.Position);
Assert.Equal(ForcedPosition, entity.Position);
// M1 (architecture review round 2): ForcedCell genuinely differs
// from the spawn Cell — this assertion is independently
// falsifiable, verified by isolating it ahead of the position
// asserts under the same receipt->render sabotage: it fails on its
// own (entity.ParentCellId stays at the spawn Cell), not merely
// alongside the position assertion.
Assert.NotEqual(Cell, entity.ParentCellId);
Assert.Equal(ForcedCell, entity.ParentCellId);
Assert.True(record.IsSpatiallyProjected);
Assert.True(record.IsSpatiallyVisible);
}
private static WorldSession.EntityPositionUpdate ForceUpdate(
Vector3 position,
ushort positionSequence = 2,
ushort forcePositionSequence = 1) =>
new(
PlayerGuid,
new CreateObject.ServerPosition(
Cell,
position.X,
position.Y,
position.Z,
1f,
0f,
0f,
0f),
Velocity: null,
PlacementId: null,
IsGrounded: true,
InstanceSequence: 1,
PositionSequence: positionSequence,
TeleportSequence: 0,
ForcePositionSequence: forcePositionSequence);
private static WorldSession.EntitySpawn Spawn(uint guid, uint cell)
{
var position = new CreateObject.ServerPosition(
cell, 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: 0x02000001u,
MotionTableId: 0x09000001u,
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,
0x02000001u,
[],
[],
[],
null,
null,
"force-position fixture",
(uint)ItemType.Creature,
null,
0x09000001u,
PhysicsState: (uint)PhysicsStateFlags.ReportCollisions,
InstanceSequence: 1,
MovementSequence: 1,
ServerControlSequence: 1,
PositionSequence: 1,
Physics: physics);
}
///
/// Mirrors RuntimeFirstEntryHostIntegrationTests.HostFixture's
/// established composition (bare
/// + REAL + REAL
/// ), extended with a
/// constructed
/// against the SAME entity objects, movement state, and generation —
/// exactly the shape RuntimeAcceptedPositionDriveControllerTests
/// .CreateAcceptedPositionDrive uses in Runtime.Tests, adapted to
/// the App-layer bare-lifetime pattern instead of a full
/// GameRuntime.
///
private sealed class HostFixture : IDisposable
{
internal readonly RuntimeEntityObjectLifetime EntityObjects = new();
internal readonly LiveEntityRuntime Runtime;
internal readonly LiveEntityHydrationController Controller;
internal readonly AcDream.Runtime.Session.RuntimeFirstEntryDriveController
FirstEntry;
internal readonly RuntimeAcceptedPositionDriveController Drive;
internal readonly RuntimeLocalPlayerMovementState Movement;
internal readonly WorldGameState WorldState = new();
private readonly WorldSession _session;
internal HostFixture()
{
EntityObjects.BindEventContext(
static () => new RuntimeGenerationToken(1UL),
static () => 1UL);
EntityObjects.Physics.SetPosition.BeginCollisionGeneration(
Cell & 0xFFFF0000u, 1UL);
EntityObjects.Physics.Engine.AddLandblock(
Cell & 0xFFFF0000u,
new TerrainSurface(new byte[81], new float[256]),
Array.Empty(),
Array.Empty(),
worldOffsetX: 0f,
worldOffsetY: 0f);
EntityObjects.Physics.SetPosition.CommitCollisionGeneration(
Cell & 0xFFFF0000u, 1UL, ready: true);
EntityObjects.Physics.ObserveLocalWorldFrame(
Cell, teleportAdvanced: false);
Movement = new RuntimeLocalPlayerMovementState();
var runtimeIdentity = new RuntimeLocalPlayerIdentityState();
var publication = new RuntimeLocalPlayerPhysicsPublicationState(
EntityObjects.Entities,
EntityObjects.Physics,
Movement,
runtimeIdentity);
Movement.AttachPhysicsPublication(publication);
EntityObjects.LocalPlayerFirstEntry.BindPublication(publication);
runtimeIdentity.ServerGuid = PlayerGuid;
var spatial = new GpuWorldState();
spatial.AddLandblock(new LoadedLandblock(
(Cell & 0xFFFF0000u) | 0xFFFFu,
new LandBlock(),
Array.Empty()));
Runtime = new LiveEntityRuntime(
spatial,
new NoopResources(),
EntityObjects);
FirstEntry = new AcDream.Runtime.Session.RuntimeFirstEntryDriveController(
EntityObjects,
new GameRuntimeClock(),
new UnusedCollisionSource(),
static () => PlayerMovementConstructionOptions.Fallback,
static _ => new RuntimeLocalPlayerPhysicsActivationPreparation(
0.48f,
1.835f,
RuntimeLocalPlayerShadowDisposition.ProvenShapeless));
var localShadowState = new LocalPlayerShadowState();
var localShadowIdentity = new LocalPlayerIdentityState
{
ServerGuid = PlayerGuid,
};
var localShadowOrigin = new LiveWorldOriginState();
localShadowOrigin.SetPlaceholder(0, 0);
var localShadowSynchronizer = new LocalPlayerShadowSynchronizer(
EntityObjects.Physics.Engine,
Runtime,
localShadowIdentity,
localShadowOrigin,
localShadowState);
var sink = new RuntimePlacementPresentationSink(
Runtime,
new RuntimeWorldTransitState(),
WorldState,
new WorldEvents(),
new EntityEffectPoseRegistry(),
localShadowSynchronizer,
() => PlayerGuid,
_ => { },
[(_, _) => { }]);
_ = new AcDream.Runtime.Physics.RuntimePlacementProjectionSubscription(
EntityObjects.Placements,
static () => new RuntimeGenerationToken(1UL),
sink);
var materializer = new HostMaterializer(Runtime);
var identity = new LocalPlayerIdentityState { ServerGuid = PlayerGuid };
var dormant = new DormantLiveEntityStore();
var deletion = new LiveEntityDeletionController(
Runtime,
EntityObjects,
new NoopTeardown(),
identity,
dormant);
Controller = new LiveEntityHydrationController(
Runtime,
EntityObjects,
new object(),
materializer,
new NoopRelationships(),
new AcceptingReady(),
new KnownOrigin(),
new NoopNetworkSink(),
new NoopTimestamps(),
identity,
deletion,
dormant,
firstEntry: FirstEntry);
_session = new WorldSession(
new IPEndPoint(IPAddress.Loopback, 9000),
new FixtureTransport())
{
// Phase I.3 test seam: intercepts the outbound ack body
// before the wire-write path, which would otherwise NPE on
// an unseeded ISAAC keystream (this fixture never runs a
// real Connect() handshake). This test's subject is the
// canonical commit -> render entity chain, not the outbound
// ack itself.
GameActionCapture = _ => { },
};
Drive = new RuntimeAcceptedPositionDriveController(
EntityObjects,
new GameRuntimeClock(),
new UnusedCollisionSource(),
new LocalPlayerOutboundController((_, _, _, _, _, _) => { }),
static () => new RuntimeGenerationToken(1UL),
static () => PlayerGuid,
() => Movement.Controller,
// usePositionFromServer: true (autonomy level 2) suppresses
// the outbound ack this test doesn't exercise — the fixture
// WorldSession never negotiates ISAAC (no real Connect()),
// so an attempted send would throw. This test's subject is
// the canonical commit -> render entity chain, not the
// outbound ack (that is AP-144's own separately-filed row).
static () => true,
() => _session);
}
public void Dispose()
{
_session.Dispose();
try
{
Runtime.Clear();
}
catch
{
// Failure-path assertions are made before Dispose runs.
}
}
}
private sealed class HostMaterializer(LiveEntityRuntime runtime)
: ILiveEntityProjectionMaterializer
{
public bool TryMaterialize(
RuntimeEntityRecord expectedCanonical,
WorldSession.EntitySpawn canonicalSpawn,
LiveProjectionPurpose purpose,
ulong expectedCreateIntegrationVersion,
AcDream.App.Rendering.LiveEntityAppearanceUpdateState? appearanceUpdate = null)
{
if (canonicalSpawn.Position is not { } position
|| canonicalSpawn.SetupTableId is null)
{
return false;
}
WorldEntity? entity = runtime.MaterializeLiveEntity(
expectedCanonical,
position.LandblockId,
id => new WorldEntity
{
Id = id,
ServerGuid = canonicalSpawn.Guid,
SourceGfxObjOrSetupId = canonicalSpawn.SetupTableId.Value,
Position = new Vector3(
position.PositionX,
position.PositionY,
position.PositionZ),
Rotation = Quaternion.Identity,
MeshRefs = [],
ParentCellId = position.LandblockId,
},
LiveEntityProjectionKind.World,
initializeProjection: null,
out LiveEntityRecord? record,
LiveEntityMaterializationResidence.AwaitRuntimePlacement);
if (entity is null || record is null)
return false;
if (runtime.IsCurrentCreateIntegration(
expectedCanonical,
expectedCreateIntegrationVersion)
&& expectedCanonical.FullCellId != 0u
&& !runtime.HasActiveInitialCreateResidence(expectedCanonical)
&& !runtime.RebucketLiveEntity(
canonicalSpawn.Guid,
expectedCanonical.FullCellId))
{
return false;
}
return runtime.IsCurrentRecord(record);
}
public void ResetSessionState()
{
}
}
private sealed class NoopResources : ILiveEntityResourceLifecycle
{
public void Register(WorldEntity entity)
{
}
public void Unregister(WorldEntity entity)
{
}
}
private sealed class NoopTeardown : ILiveEntityTeardownCoordinator
{
public void TearDown(LiveEntityRecord record)
{
}
public void ForgetUnknownOwner(uint serverGuid)
{
}
}
private sealed class NoopRelationships : ILiveEntityRelationshipProjection
{
public void OnSpawn(WorldSession.EntitySpawn spawn)
{
}
public void OnParent(ParentEvent.Parsed update)
{
}
public void OnCreateParentAccepted(CreateParentUpdate update)
{
}
public ChildUnparentDisposition OnChildBecameUnparented(uint childGuid) =>
ChildUnparentDisposition.Completed;
public bool TryApplyAttachedAppearance(
LiveEntityRecord record,
ulong objDescAuthorityVersion) => false;
}
private sealed class AcceptingReady : ILiveEntityReadyPublisher
{
public bool Publish(LiveEntityReadyCandidate candidate) => true;
}
private sealed class KnownOrigin : ILiveEntityWorldOriginCoordinator
{
public bool IsKnown => true;
public LiveEntityOriginInitialization TryInitialize(
WorldSession.EntitySpawn spawn) => new(true, []);
}
private sealed class NoopNetworkSink : ILiveEntityNetworkUpdateSink
{
public void ApplySameGeneration(SameGenerationCreateObjectEvents events)
{
}
}
private sealed class NoopTimestamps : IAcceptedLocalPhysicsTimestampPublisher
{
public void Publish(uint serverGuid, AcceptedPhysicsTimestamps timestamps)
{
}
}
private sealed class UnusedCollisionSource : IPreparedCollisionSource
{
public PreparedAssetPresence ProbeCollision(
PakAssetType type,
uint sourceFileId) => PreparedAssetPresence.Available;
public PreparedCollisionReadResult ReadSetupCollision(
uint sourceFileId,
CancellationToken cancellationToken = default) =>
PreparedCollisionReadResult.Loaded(
new FlatSetupCollision(
System.Collections.Immutable.ImmutableArray<
FlatCollisionCylinder>.Empty,
[new FlatCollisionSphere(Vector3.Zero, 0.48f)],
height: 0f,
radius: 0f,
stepUpHeight: 0.4f,
stepDownHeight: 0.4f));
public PreparedCollisionReadResult
ReadGfxObjCollision(
uint sourceFileId,
CancellationToken cancellationToken = default) =>
throw new NotSupportedException();
public PreparedCollisionReadResult
ReadCellStructureCollision(
uint sourceFileId,
CancellationToken cancellationToken = default) =>
throw new NotSupportedException();
public PreparedCollisionReadResult ReadEnvCellTopology(
uint sourceFileId,
CancellationToken cancellationToken = default) =>
throw new NotSupportedException();
public PreparedCollisionSourceStats CollisionStats => default;
public void Dispose()
{
}
}
private sealed class FixtureTransport : IWorldSessionTransport
{
public void Send(ReadOnlySpan datagram)
{
}
public void Send(
IPEndPoint remote,
ReadOnlySpan datagram)
{
}
public int Receive(
Span destination,
TimeSpan timeout,
out IPEndPoint? from)
{
from = null;
return -1;
}
public ValueTask ReceiveAsync(
Memory destination,
CancellationToken cancellationToken) =>
ValueTask.FromException(
new OperationCanceledException(cancellationToken));
public void Dispose()
{
}
}
}