using AcDream.App.Streaming; using AcDream.App.World; using AcDream.Core.Physics; using AcDream.Runtime.Entities; namespace AcDream.App.Tests; /// /// Explicit isolated lifetime-group seam for App projection tests. Production /// composition supplies its session-owned group from GameWindow; focused tests /// use a fresh group per runtime so identity never leaks between fixtures. /// internal static class LiveEntityRuntimeFixture { /// /// C3c: initial-Create registration now begins the canonical residence /// lease, whose admission requires a live session generation. Focused /// App fixtures bind a fixed non-zero token exactly like the Runtime /// conductor fixtures do. /// private static RuntimeEntityObjectLifetime WithGeneration( RuntimeEntityObjectLifetime lifetime) { lifetime.BindEventContext( static () => new AcDream.Runtime.RuntimeGenerationToken(1UL), static () => 1UL); return lifetime; } public static LiveEntityRuntime Create( GpuWorldState spatial, ILiveEntityResourceLifecycle resources, uint firstLocalEntityId = RuntimeEntityDirectory.FirstLocalEntityId) { var lifetime = WithGeneration( new RuntimeEntityObjectLifetime(firstLocalEntityId)); return new LiveEntityRuntime(spatial, resources, lifetime); } /// /// C3c: a runtime whose initial-create residences can actually be driven /// to completion — collision generation committed for /// , the production /// /// constructed against the lifetime, and an acknowledge-only placement /// subscription mirroring the host rules (Discard/ExecutorCompleted /// acknowledged; Place/Withdraw left at the head for the conductors). /// Tests exercising post-residence legacy update paths register, then /// call to complete the /// conductors exactly like the composed host's Create-transaction pump. /// internal sealed class DrivenLiveEntityRuntime { internal required LiveEntityRuntime Runtime { get; init; } internal required RuntimeEntityObjectLifetime Lifetime { get; init; } internal required AcDream.Runtime.Session.RuntimeFirstEntryDriveController FirstEntry { get; init; } internal required AcDream.Runtime.Physics .RuntimePlacementProjectionSubscription Subscription { get; init; } internal void Pump() => FirstEntry.DriveAll(); } public static DrivenLiveEntityRuntime CreateDriven( GpuWorldState spatial, ILiveEntityResourceLifecycle resources, uint landblockId = 0x01010000u) { var lifetime = WithGeneration(new RuntimeEntityObjectLifetime()); lifetime.Physics.SetPosition.BeginCollisionGeneration( landblockId & 0xFFFF0000u, 1UL); lifetime.Physics.Engine.AddLandblock( landblockId & 0xFFFF0000u, new AcDream.Core.Physics.TerrainSurface( new byte[81], new float[256]), Array.Empty(), Array.Empty(), worldOffsetX: 0f, worldOffsetY: 0f); lifetime.Physics.SetPosition.CommitCollisionGeneration( landblockId & 0xFFFF0000u, 1UL, ready: true); // 670f307c: Create frames are landblock-local, so a first-entry // conductor resolves them through Runtime's world frame // (RuntimeSetPositionState.PrepareMover:1526-1544) and parks on // RetrySetupUnavailable until that frame exists. Only the accepted // local-player Create publishes it // (RuntimeEntityObjectLifetime.RegisterEntityCore:558-570 -> // RuntimePhysicsState.ObserveLocalWorldFrame), and production always // registers the player before driving any broadcast Create. Model // that ambient world fact beside the resident landblock above rather // than registering a second entity, which would consume a local // entity id and perturb every exact-ledger assertion built on this // fixture. RuntimeWorldFrameTests covers the real ordering. lifetime.Physics.ObserveLocalWorldFrame( (landblockId & 0xFFFF0000u) | 0x0001u, teleportAdvanced: false); var runtime = new LiveEntityRuntime(spatial, resources, lifetime); var movement = new AcDream.Runtime.Gameplay .RuntimeLocalPlayerMovementState(); var identity = new AcDream.Runtime.Gameplay .RuntimeLocalPlayerIdentityState(); var publication = new AcDream.Runtime.Gameplay .RuntimeLocalPlayerPhysicsPublicationState( lifetime.Entities, lifetime.Physics, movement, identity); movement.AttachPhysicsPublication(publication); lifetime.LocalPlayerFirstEntry.BindPublication(publication); var firstEntry = new AcDream.Runtime.Session .RuntimeFirstEntryDriveController( lifetime, new AcDream.Runtime.GameRuntimeClock(), new SphereCollisionSource(), static () => AcDream.Runtime.Gameplay .PlayerMovementConstructionOptions.Fallback, static _ => new AcDream.Runtime.Gameplay .RuntimeLocalPlayerPhysicsActivationPreparation( 0.48f, 1.835f, AcDream.Runtime.Gameplay .RuntimeLocalPlayerShadowDisposition .ProvenShapeless)); var subscription = new AcDream.Runtime.Physics .RuntimePlacementProjectionSubscription( lifetime.Placements, static () => new AcDream.Runtime.RuntimeGenerationToken(1UL), new AckOnlyPlacementSink(runtime)); return new DrivenLiveEntityRuntime { Runtime = runtime, Lifetime = lifetime, FirstEntry = firstEntry, Subscription = subscription, }; } private sealed class AckOnlyPlacementSink(LiveEntityRuntime runtime) : AcDream.Runtime.Physics.IRuntimePlacementProjectionSink { public bool TryApply( in AcDream.Runtime.Physics.RuntimePlacementProjectionSnapshot projection) { if (projection.Kind is AcDream.Runtime.Physics .RuntimePlacementProjectionKind.Discard) { return true; } if (projection.Kind is AcDream.Runtime.Physics .RuntimePlacementProjectionKind.ExecutorCompleted) { return projection.Token.ExactCellId == 0u || runtime.TryApplyInitialCreateCompletionPresentation( in projection); } return !runtime.HasActiveInitialCreateResidence( projection.Token.Entity) && runtime.TryApplyRuntimePlacementProjection(in projection); } } private sealed class SphereCollisionSource : AcDream.Content.IPreparedCollisionSource { public AcDream.Content.PreparedAssetPresence ProbeCollision( AcDream.Content.Pak.PakAssetType type, uint sourceFileId) => AcDream.Content.PreparedAssetPresence.Available; public AcDream.Content.PreparedCollisionReadResult< AcDream.Core.Physics.FlatSetupCollision> ReadSetupCollision( uint sourceFileId, CancellationToken cancellationToken = default) => AcDream.Content.PreparedCollisionReadResult< AcDream.Core.Physics.FlatSetupCollision>.Loaded( new AcDream.Core.Physics.FlatSetupCollision( System.Collections.Immutable.ImmutableArray< AcDream.Core.Physics.FlatCollisionCylinder>.Empty, [new AcDream.Core.Physics.FlatCollisionSphere( System.Numerics.Vector3.Zero, 0.48f)], height: 0f, radius: 0f, stepUpHeight: 0.4f, stepDownHeight: 0.4f)); public AcDream.Content.PreparedCollisionReadResult< AcDream.Core.Physics.FlatGfxObjCollisionAsset> ReadGfxObjCollision( uint sourceFileId, CancellationToken cancellationToken = default) => throw new NotSupportedException(); public AcDream.Content.PreparedCollisionReadResult< AcDream.Core.Physics.FlatCellStructureCollisionAsset> ReadCellStructureCollision( uint sourceFileId, CancellationToken cancellationToken = default) => throw new NotSupportedException(); public AcDream.Content.PreparedCollisionReadResult< AcDream.Core.Physics.FlatEnvCellTopology> ReadEnvCellTopology( uint sourceFileId, CancellationToken cancellationToken = default) => throw new NotSupportedException(); public AcDream.Content.PreparedCollisionSourceStats CollisionStats => default; public void Dispose() { } } public static LiveEntityRuntime Create( GpuWorldState spatial, ILiveEntityResourceLifecycle resources, PhysicsEngine physicsEngine, uint firstLocalEntityId = RuntimeEntityDirectory.FirstLocalEntityId) { var lifetime = WithGeneration(new RuntimeEntityObjectLifetime( physicsEngine, firstLocalEntityId)); return new LiveEntityRuntime(spatial, resources, lifetime); } public static LiveEntityRuntime Create( GpuWorldState spatial, ILiveEntityResourceLifecycle resources, Action tearDownRuntimeComponents, uint firstLocalEntityId = RuntimeEntityDirectory.FirstLocalEntityId) { var lifetime = WithGeneration( new RuntimeEntityObjectLifetime(firstLocalEntityId)); return new LiveEntityRuntime( spatial, resources, tearDownRuntimeComponents, lifetime); } public static LiveEntityRuntime Create( GpuWorldState spatial, ILiveEntityResourceLifecycle resources, ILiveEntityRuntimeComponentLifecycle runtimeComponentLifecycle, uint firstLocalEntityId = RuntimeEntityDirectory.FirstLocalEntityId) { var lifetime = WithGeneration( new RuntimeEntityObjectLifetime(firstLocalEntityId)); return new LiveEntityRuntime( spatial, resources, runtimeComponentLifecycle, lifetime); } public static LiveEntityRuntime Create( GpuWorldState spatial, ILiveEntityResourceLifecycle resources, ILiveEntityRuntimeComponentLifecycle runtimeComponentLifecycle, PhysicsEngine physicsEngine, uint firstLocalEntityId = RuntimeEntityDirectory.FirstLocalEntityId) { var lifetime = WithGeneration(new RuntimeEntityObjectLifetime( physicsEngine, firstLocalEntityId)); return new LiveEntityRuntime( spatial, resources, runtimeComponentLifecycle, lifetime); } }