using System.Numerics; using AcDream.Content; using AcDream.Content.Pak; using AcDream.Core.Net; using AcDream.Core.Net.Messages; using AcDream.Core.Physics; using AcDream.Runtime; using AcDream.Runtime.Entities; using AcDream.Runtime.Physics; using AcDream.Runtime.Session; namespace AcDream.App.Tests.Physics; /// /// C4 route 4b-2: a REAL /// over a bare /// , so App-layer acceptance tests /// drive the production far-snap path end to end instead of simulating it. /// Mirrors RuntimeRemotePlacementDriveControllerTests' own fixture. /// internal sealed class RemotePlacementDriveFixture : IDisposable { internal const uint SourceLandblock = 0xB1000000u; internal const uint SourceCell = SourceLandblock | 0x0001u; internal const uint DestinationLandblock = 0xB2000000u; internal const uint DestinationCell = DestinationLandblock | 0x0001u; /// The +X world offset /// gives the destination landblock, so a committed placement's world /// position is the authored local position plus this. internal static readonly Vector3 DestinationWorldOffset = new(192f, 0f, 0f); internal const float SpawnHeight = 7f; private readonly ServiceWindow _window = new(); internal RemotePlacementDriveFixture() { Lifetime = new RuntimeEntityObjectLifetime(FlatEngine()); Drive = new RuntimeRemotePlacementDriveController( Lifetime, new GameRuntimeClock(), new UnusedCollisionSource(), _window); } internal RuntimeEntityObjectLifetime Lifetime { get; } internal RuntimeRemotePlacementDriveController Drive { get; } internal void AllowDestination() => _window.Allow(DestinationLandblock); /// /// Commits the destination landblock's collision generation and observes /// the source world frame once, so a placement into /// can actually resolve. /// internal void PublishDestinationCollision() { 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; Lifetime.Physics.ObserveLocalWorldFrame( SourceCell, teleportAdvanced: false); Lifetime.Physics.SetPosition.BeginCollisionGeneration( DestinationLandblock, 1UL); Lifetime.Physics.Engine.AddLandblock( DestinationLandblock, new TerrainSurface(heights, heightTable), Array.Empty(), Array.Empty(), worldOffsetX: DestinationWorldOffset.X, worldOffsetY: DestinationWorldOffset.Y); Lifetime.Physics.SetPosition.CommitCollisionGeneration( DestinationLandblock, 1UL, ready: true); } /// /// Registers one remote incarnation with a canonical body, its shared /// , and the accepted destination already merged /// onto its snapshot — exactly the state /// RuntimeEntityObjectLifetime.TryApplyPosition leaves behind /// before OnPosition routes the packet. /// internal (RuntimeEntityRecord Record, RemoteMotion Remote, PhysicsBody Body) AddRemote(uint guid, Vector3 destination) { RuntimeEntityRecord record = Lifetime.RegisterEntity( Spawn(guid)).Canonical!; Lifetime.Entities.SetFinalPhysicsState(record, PhysicsStateFlags.Gravity); Lifetime.Entities.SetFullCell( record, SourceCell, (SourceCell & 0xFFFF0000u) | 0xFFFFu); var body = new PhysicsBody { Position = new Vector3(10f, 10f, SpawnHeight), Orientation = Quaternion.Identity, LastUpdateTime = 1d, State = PhysicsStateFlags.Gravity, // AP-140 (retired 2026-08-04): the remote stands on the flat // source landblock, so the sweep's SetPositionInternal commit // would derive CONTACT (`contact_plane_valid` @0x00515430) and // ON_WALKABLE (`contact_plane.N.z >= floor_z` // @0x00515465-0x0051548E) for it. Both bits now have to be // present, because the accepted-Position routing gates read // retail's CONTACT predicate // (`InterpolationManager::adjust_offset` @0x00555D52) rather than // the client `Airborne` walkability flag: a body with a bare // `Active` transient state is in FREE FLIGHT and every routing // test would take the free-flight snap arm. Tests that want free // flight clear these explicitly. TransientState = TransientStateFlags.Active | TransientStateFlags.Contact | TransientStateFlags.OnWalkable, }; body.SnapToCell(SourceCell, body.Position, body.Position); Lifetime.Entities.SetPhysicsBody(record, body); record.ObjectClock.Activate(); Lifetime.Physics.AcknowledgeSpatialProjection(record, spatial: true); record.Snapshot = record.Snapshot with { Position = new CreateObject.ServerPosition( DestinationCell, destination.X, destination.Y, destination.Z, 1f, 0f, 0f, 0f), }; RemoteMotion remote = Lifetime.Physics.GetOrCreateRemoteMotion(record); // Past AP-87's firstUp hint, so the 4 m body-to-target guard is the // condition under test rather than the first-sample one. remote.LastServerPosTime = 1_700_000_000d; return (record, remote, body); } /// /// Stands in for the production placement-projection subscription this /// bare fixture never wires. /// internal void DrainPlacementFifo() { while (Lifetime.Physics.SetPosition.TryPeekProjection( out RuntimePlacementProjectionSnapshot head)) { if (!Lifetime.Physics.SetPosition.AcknowledgeProjection(head.Token)) break; } } internal int LiveOperationCount => Lifetime.Physics.CaptureOwnership().SetPositionOperationCount; internal int RemotePlacementLedger => Lifetime.CaptureOwnership().RemotePlacementDrivePendingCount; public void Dispose() => Lifetime.Dispose(); private static WorldSession.EntitySpawn Spawn(uint guid) => new( guid, new CreateObject.ServerPosition( SourceCell, 10f, 10f, SpawnHeight, 1f, 0f, 0f, 0f), SetupTableId: null, AnimPartChanges: Array.Empty(), TextureChanges: Array.Empty(), SubPalettes: Array.Empty(), BasePaletteId: null, ObjScale: null, Name: "remote", ItemType: null, MotionState: null, MotionTableId: 0x09000001u); private static PhysicsEngine FlatEngine() { var engine = new PhysicsEngine { DataCache = new PhysicsDataCache() }; engine.AddLandblock( SourceLandblock, new TerrainSurface(new byte[81], new float[256]), Array.Empty(), Array.Empty(), worldOffsetX: 0f, worldOffsetY: 0f); return engine; } private sealed class ServiceWindow : IRuntimeRemotePlacementServiceWindow { private readonly HashSet _within = []; internal void Allow(uint landblockId) => _within.Add((landblockId & 0xFFFF0000u) | 0xFFFFu); public bool IsWithinServiceWindow(uint landblockId) => _within.Contains((landblockId & 0xFFFF0000u) | 0xFFFFu); } private sealed class UnusedCollisionSource : IPreparedCollisionSource { public PreparedAssetPresence ProbeCollision( PakAssetType type, uint sourceFileId) => PreparedAssetPresence.Available; public PreparedCollisionReadResult ReadSetupCollision( uint sourceFileId, CancellationToken cancellationToken = default) => PreparedCollisionReadResult.Missing; 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() { } } }