acdream/tests/AcDream.App.Tests/World/RuntimeFirstEntryHostIntegrationTests.cs
Erik 6dcb94ac1b test(runtime): restore the world-frame precondition across first-entry fixtures
670f307c made remote first-entry placement resolve its landblock-local
CreateObject origin through Runtime's world frame
(RuntimeSetPositionState.PrepareMover:1526-1544) and return
RetrySetupUnavailable until that frame exists. Only the accepted local-player
Create publishes it (RuntimeEntityObjectLifetime.RegisterEntityCore:558-570 ->
RuntimePhysicsState.ObserveLocalWorldFrame).

Fixtures that drive remote conductors in a world with no local player - a
state production never occupies, since the player's own Create always precedes
broadcast Creates - therefore parked forever on RetrySetupUnavailable. Their
initial-create residences never retired, which cascaded into rejected
appearance updates, missing canonical bodies, unconverged ownership ledgers,
and a GameRuntime teardown that could not complete stage 10.

The measured blast radius was far larger than the handoff recorded. It claimed
"six selected fixture failures"; a baseline run found 43. The App suite was
fully green at 01f4791e and 670f307c broke 28 tests at once; the Runtime suite
lost 13, twelve of them in RuntimeRemoteFirstEntryStateTests - the exact
conductor that commit gated. Both commits were verified on focused runs only.

The production gate is correct, so nothing here weakens it. It matches App's
own coordinate owner: LiveWorldOriginState is initialized once from the local
player's spawn (LiveEntityHydrationPorts.cs:226) and rebased only by
StreamingOriginRecenterCoordinator.Advance at a teleport boundary - exactly
ObserveLocalWorldFrame's semantics. Every fixture is repaired by supplying the
missing precondition beside the resident landblock it already models, and not
one expected value or assertion was changed.

The mechanism shipped with zero tests. RuntimeWorldFrameTests now pins its
contract: the local player publishes the frame, remotes never do, neighbouring
landblocks convert at 192 m per step, ordinary movement across a landblock
boundary must NOT rebase it, an accepted teleport must, and a zero cell id
neither publishes nor resolves. That "no rebase on ordinary movement" rule is
load-bearing - if it and LiveWorldOriginState ever disagree, remote objects
are placed a multiple of 192 m from where the world is streamed.

Runtime 1,009/1,009; App 4,048 passed / 3 skipped.

Refs #281.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 13:32:28 +02:00

759 lines
29 KiB
C#

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.Core.Plugins;
using AcDream.Core.Items;
using AcDream.Core.Net;
using AcDream.Core.Net.Messages;
using AcDream.Core.Physics;
using AcDream.Core.World;
using AcDream.Runtime.Entities;
using AcDream.Runtime.World;
using DatReaderWriter.DBObjs;
namespace AcDream.App.Tests.World;
/// <summary>
/// C3c contract integration tests: the flipped graphical host wiring driven
/// end-to-end — registration through <see cref="LiveEntityHydrationController"/>,
/// the REAL <see cref="RuntimePlacementPresentationSink"/> behind the REAL
/// <see cref="AcDream.Runtime.Physics.RuntimePlacementProjectionSubscription"/>,
/// and the production
/// <see cref="AcDream.Runtime.Session.RuntimeFirstEntryDriveController"/> pump.
/// No conductor is ever hand-called.
/// </summary>
public sealed class RuntimeFirstEntryHostIntegrationTests
{
private const uint Cell = 0x01010001u;
private const uint Guid = 0x70000301u;
[Fact]
public void InitialCreate_ResidenceConductorReceipt_BindsWorldVisibilityExactlyOnce()
{
using var fixture = new HostFixture(playerGuid: 0u);
int residencesBegan = 0;
fixture.EntityObjects.BindInitialResidenceBeginNotification(
_ => residencesBegan++);
bool visibleAtMaterialize = true;
fixture.Materializer.AfterMaterialize = record =>
{
// Clause 1: the sidecar exists but presentation stays suppressed
// until the conductor's completion receipt binds it.
visibleAtMaterialize = record.IsSpatiallyProjected
|| record.IsSpatiallyVisible;
};
fixture.Controller.OnCreate(Spawn(Guid, Cell));
Assert.Equal(1, residencesBegan);
Assert.False(visibleAtMaterialize);
Assert.True(fixture.Runtime.TryGetRecord(Guid, out LiveEntityRecord record));
// The residence was consumed by the conductor inside the Create
// transaction's own pump.
Assert.False(fixture.Runtime.HasActiveInitialCreateResidence(
record.Canonical));
Assert.Equal(Cell, record.Canonical.FullCellId);
Assert.True(record.IsSpatiallyProjected);
Assert.True(record.IsSpatiallyVisible);
Assert.NotNull(record.PhysicsBody);
Assert.Equal((record, true), Assert.Single(fixture.VisibilityEdges));
AcDream.Plugin.Abstractions.WorldEntitySnapshot snapshot =
Assert.Single(fixture.WorldState.Entities);
Assert.Equal(record.WorldEntity!.Position, snapshot.Position);
Assert.Equal(0, fixture.EntityObjects.Placements.PendingCount);
Assert.Equal(0, fixture.FirstEntry.PendingCount);
}
[Fact]
public void DeferredParentCreate_StaysInvisibleUntilParentReplay()
{
const uint parentGuid = 0x70000302u;
const uint childGuid = 0x70000303u;
using var fixture = new HostFixture(playerGuid: 0u);
int residencesBegan = 0;
fixture.EntityObjects.BindInitialResidenceBeginNotification(
_ => residencesBegan++);
fixture.Controller.OnCreate(ParentedSpawn(childGuid, parentGuid));
// Retail queues the raw blob under the parent's GUID; nothing about
// the child may escape — no canonical, no sidecar, no presentation.
Assert.Equal(0, residencesBegan);
Assert.False(fixture.Runtime.TryGetCanonical(childGuid, out _));
Assert.False(fixture.Runtime.TryGetRecord(childGuid, out _));
Assert.True(fixture.Runtime.ParentAttachments.ContainsDeferredCreate(
childGuid,
instanceSequence: 1));
Assert.Empty(fixture.WorldState.Entities);
Assert.Empty(fixture.VisibilityEdges);
fixture.Controller.OnCreate(Spawn(parentGuid, Cell));
// The replayed child's residence was recorded mid-drain; the next
// frame's pump (the per-frame retry phase) drives its conductor.
fixture.FirstEntry.DriveAll();
Assert.Equal(2, residencesBegan);
Assert.False(fixture.Runtime.ParentAttachments.ContainsDeferredCreate(
childGuid,
instanceSequence: 1));
Assert.True(fixture.Runtime.TryGetCanonical(
childGuid,
out RuntimeEntityRecord child));
Assert.False(fixture.Runtime.HasActiveInitialCreateResidence(child));
Assert.Equal(0, fixture.FirstEntry.PendingCount);
// The parented child is celless and presentation-suppressed until its
// own attach/position flow — only the parent is world-visible.
Assert.Equal(0u, child.FullCellId);
Assert.False(fixture.Runtime.TryGetRecord(childGuid, out _));
Assert.True(fixture.Runtime.TryGetRecord(
parentGuid,
out LiveEntityRecord parent));
Assert.True(parent.IsSpatiallyVisible);
Assert.Single(fixture.WorldState.Entities);
}
[Fact]
public void LocalLogin_PresentationAttachFailure_RetriesWithoutRuntimeRollback()
{
using var fixture = new HostFixture(playerGuid: Guid);
// The camera/shadow-analog App attach failure: the first
// world-visibility binding throws AFTER Runtime committed the
// controller/body/placement.
fixture.VisibilityFailuresRemaining = 1;
fixture.Controller.OnCreate(Spawn(Guid, Cell));
// Runtime is NOT rolled back by the App-side presentation failure:
// the published movement controller, canonical body, and committed
// cell all survive; only the completion receipt stays pending for
// the per-frame retry.
AcDream.Runtime.Gameplay.PlayerMovementController controller =
Assert.IsType<AcDream.Runtime.Gameplay.PlayerMovementController>(
fixture.Movement.Controller);
Assert.True(controller.IsRuntimePublished);
Assert.True(fixture.Runtime.TryGetRecord(Guid, out LiveEntityRecord record));
Assert.Equal(Cell, record.Canonical.FullCellId);
Assert.NotNull(record.PhysicsBody);
Assert.False(fixture.Runtime.HasActiveInitialCreateResidence(
record.Canonical));
Assert.Equal(1, fixture.EntityObjects.Placements.PendingCount);
Assert.Equal((record, true), Assert.Single(fixture.VisibilityEdges));
Assert.True(fixture.Subscription.RetryPending());
Assert.Same(controller, fixture.Movement.Controller);
Assert.True(controller.IsRuntimePublished);
Assert.Equal(0, fixture.EntityObjects.Placements.PendingCount);
Assert.True(record.IsSpatiallyProjected);
Assert.True(record.IsSpatiallyVisible);
Assert.Equal(2, fixture.VisibilityEdges.Count);
}
/// <summary>
/// C3c-F5: through the REAL flipped host wiring (hydration ->
/// residence -> conductor -> publication -> dormant activation), a
/// login onto flat ground must complete with retail's
/// first-gravity-frame contact (SmartBox::HandleCreateObject 0x00454C80
/// -> init_player 0x00455010 -> CPhysicsObj::enter_world 0x00516170 +
/// the first simulated frame's touch, compressed via the shared #270
/// settle) — and the outbound motion snapshot must report grounded,
/// the exact bit LocalPlayerOutboundController serializes and ACE's
/// "You can't do that while in the air!" gate reads. Spawn feet at 5
/// over a flat floor at 4.7 (0.3 m inside the settle reach), with the
/// production human bottom-sphere origin so the authored placement
/// stands clear of the floor.
/// </summary>
[Fact]
public void LocalLogin_FlatGround_ReportsGroundedOutboundContactBit()
{
using var fixture = new HostFixture(
playerGuid: Guid,
terrainHeight: 4.7f,
moverSphereOriginZ: 0.475f);
fixture.Controller.OnCreate(Spawn(Guid, Cell));
AcDream.Runtime.Gameplay.PlayerMovementController controller =
Assert.IsType<AcDream.Runtime.Gameplay.PlayerMovementController>(
fixture.Movement.Controller);
Assert.True(controller.IsRuntimePublished);
Assert.True(fixture.Runtime.TryGetRecord(
Guid,
out LiveEntityRecord record));
PhysicsBody body = Assert.IsType<PhysicsBody>(record.PhysicsBody);
Assert.True(body.InWorld);
Assert.True(body.InContact);
Assert.True(body.OnWalkable);
Assert.True(body.ContactPlaneValid);
Assert.InRange(body.Position.Z, 4.65f, 4.76f);
Assert.True(controller.CanSendPositionEvent);
Assert.True(controller.CaptureMovementResult(
mouseLookEvent: false).IsOnGround);
Assert.Equal(0, fixture.FirstEntry.PendingCount);
}
/// <summary>
/// C3c-F5 counterpart through the same real wiring: a login spawn with
/// no floor within the settle's reach stays genuinely airborne — no
/// forced grounding anywhere in the first-entry sequence.
/// </summary>
[Fact]
public void LocalLogin_AirborneSpawn_StaysGenuinelyAirborne()
{
using var fixture = new HostFixture(
playerGuid: Guid,
moverSphereOriginZ: 0.475f);
fixture.Controller.OnCreate(Spawn(Guid, Cell));
AcDream.Runtime.Gameplay.PlayerMovementController controller =
Assert.IsType<AcDream.Runtime.Gameplay.PlayerMovementController>(
fixture.Movement.Controller);
Assert.True(controller.IsRuntimePublished);
Assert.True(fixture.Runtime.TryGetRecord(
Guid,
out LiveEntityRecord record));
PhysicsBody body = Assert.IsType<PhysicsBody>(record.PhysicsBody);
Assert.True(body.InWorld);
Assert.False(body.InContact);
Assert.False(body.OnWalkable);
Assert.False(controller.CanSendPositionEvent);
Assert.False(controller.CaptureMovementResult(
mouseLookEvent: false).IsOnGround);
}
[Fact]
public void GraphicalAndDirectHosts_CommitIdenticalFirstEntryRuntimeFacts()
{
// Graphical host: full flipped wiring.
using var graphical = new HostFixture(playerGuid: 0u);
graphical.Controller.OnCreate(Spawn(Guid, Cell));
Assert.True(graphical.Runtime.TryGetCanonical(
Guid,
out RuntimeEntityRecord graphicalRecord));
// Direct (no-window) host: the same canonical machinery with no
// presentation at all — registration, drive pump, ack-only
// subscription (the headless host shape).
LiveEntityRuntimeFixture.DrivenLiveEntityRuntime direct =
LiveEntityRuntimeFixture.CreateDriven(
new GpuWorldState(),
new NoopResources());
RuntimeEntityRecord directRecord = Assert.IsType<RuntimeEntityRecord>(
direct.Lifetime.RegisterEntityWithInitialResidence(
Spawn(Guid, Cell),
isLocalPlayer: false).Canonical);
Assert.True(direct.Lifetime.ApplyAcceptedSpawn(
directRecord,
directRecord.CreateIntegrationVersion,
directRecord.Snapshot,
replaceGeneration: false));
direct.Pump();
Assert.Equal(
FirstEntryFacts.Capture(graphicalRecord),
FirstEntryFacts.Capture(directRecord));
Assert.False(graphical.Runtime.HasActiveInitialCreateResidence(
graphicalRecord));
Assert.Equal(0, direct.FirstEntry.PendingCount);
Assert.Equal(0, graphical.FirstEntry.PendingCount);
}
private readonly record struct FirstEntryFacts(
uint ServerGuid,
ushort Incarnation,
uint? LocalEntityId,
uint FullCellId,
uint CanonicalLandblockId,
ulong PositionAuthorityVersion,
ulong PlacementCommitVersion,
ulong CreateIntegrationVersion,
ushort SnapshotPositionSequence,
bool HasBody,
Vector3 BodyPosition,
Quaternion BodyOrientation,
PhysicsStateFlags BodyState,
bool BodyInWorld)
{
internal static FirstEntryFacts Capture(RuntimeEntityRecord record) =>
new(
record.ServerGuid,
record.Incarnation,
record.LocalEntityId,
record.FullCellId,
record.CanonicalLandblockId,
record.PositionAuthorityVersion,
record.PlacementCommitVersion,
record.CreateIntegrationVersion,
record.Snapshot.PositionSequence,
record.PhysicsBody is not null,
record.PhysicsBody?.Position ?? default,
record.PhysicsBody?.Orientation ?? default,
record.PhysicsBody?.State ?? default,
record.PhysicsBody?.InWorld ?? false);
}
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,
"first entry",
(uint)ItemType.Creature,
null,
0x09000001u,
PhysicsState: (uint)PhysicsStateFlags.ReportCollisions,
InstanceSequence: 1,
MovementSequence: 1,
ServerControlSequence: 1,
PositionSequence: 1,
Physics: physics);
}
private static WorldSession.EntitySpawn ParentedSpawn(
uint guid,
uint parentGuid)
{
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: null,
Movement: null,
AnimationFrame: 1u,
SetupTableId: 0x02000001u,
MotionTableId: 0x09000001u,
SoundTableId: null,
PhysicsScriptTableId: null,
Parent: new PhysicsAttachment(parentGuid, LocationId: 1u),
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,
SetupTableId: 0x02000001u,
AnimPartChanges: [],
TextureChanges: [],
SubPalettes: [],
BasePaletteId: null,
ObjScale: null,
Name: "deferred child",
ItemType: (uint)ItemType.Creature,
MotionState: null,
MotionTableId: 0x09000001u,
PhysicsState: (uint)PhysicsStateFlags.ReportCollisions,
InstanceSequence: 1,
MovementSequence: 1,
ServerControlSequence: 1,
PositionSequence: 1,
ParentGuid: parentGuid,
ParentLocation: 1u,
PlacementId: 1u,
Physics: physics);
}
private sealed class HostFixture : IDisposable
{
internal readonly RuntimeEntityObjectLifetime EntityObjects = new();
internal readonly LiveEntityRuntime Runtime;
internal readonly LiveEntityHydrationController Controller;
internal readonly HostMaterializer Materializer;
internal readonly AcDream.Runtime.Session.RuntimeFirstEntryDriveController
FirstEntry;
internal readonly AcDream.Runtime.Physics
.RuntimePlacementProjectionSubscription Subscription;
internal readonly AcDream.Runtime.Gameplay.RuntimeLocalPlayerMovementState
Movement;
internal readonly WorldGameState WorldState = new();
internal readonly List<(LiveEntityRecord Record, bool Visible)>
VisibilityEdges = [];
internal int VisibilityFailuresRemaining;
internal HostFixture(
uint playerGuid,
float terrainHeight = 0f,
float moverSphereOriginZ = 0f)
{
EntityObjects.BindEventContext(
static () => new AcDream.Runtime.RuntimeGenerationToken(1UL),
static () => 1UL);
EntityObjects.Physics.SetPosition.BeginCollisionGeneration(
Cell & 0xFFFF0000u, 1UL);
EntityObjects.Physics.Engine.AddLandblock(
Cell & 0xFFFF0000u,
new TerrainSurface(
new byte[81],
Enumerable.Repeat(terrainHeight, 256).ToArray()),
Array.Empty<CellSurface>(),
Array.Empty<PortalPlane>(),
worldOffsetX: 0f,
worldOffsetY: 0f);
EntityObjects.Physics.SetPosition.CommitCollisionGeneration(
Cell & 0xFFFF0000u, 1UL, ready: true);
// 670f307c: a first-entry conductor resolves its landblock-local
// Create origin through Runtime's world frame
// (RuntimeSetPositionState.PrepareMover:1526-1544) and parks on
// RetrySetupUnavailable until it exists. Production publishes it
// from the accepted local-player Create
// (RuntimeEntityObjectLifetime.RegisterEntityCore:558-570). The
// playerGuid: 0 cases below deliberately model a REMOTE entity,
// so the frame must come from the ambient world here exactly as
// it does in LiveEntityRuntimeFixture — otherwise the graphical
// and direct hosts under comparison would differ only by a
// missing precondition. RuntimeWorldFrameTests covers the real
// local-player ordering.
EntityObjects.Physics.ObserveLocalWorldFrame(
Cell,
teleportAdvanced: false);
Movement = new AcDream.Runtime.Gameplay
.RuntimeLocalPlayerMovementState();
var runtimeIdentity = new AcDream.Runtime.Gameplay
.RuntimeLocalPlayerIdentityState();
var publication = new AcDream.Runtime.Gameplay
.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<WorldEntity>()));
Runtime = new LiveEntityRuntime(
spatial,
new NoopResources(),
EntityObjects);
FirstEntry = new AcDream.Runtime.Session
.RuntimeFirstEntryDriveController(
EntityObjects,
new AcDream.Runtime.GameRuntimeClock(),
new SphereCollisionSource(moverSphereOriginZ),
static () => AcDream.Runtime.Gameplay
.PlayerMovementConstructionOptions.Fallback,
static _ => new AcDream.Runtime.Gameplay
.RuntimeLocalPlayerPhysicsActivationPreparation(
0.48f,
1.835f,
AcDream.Runtime.Gameplay
.RuntimeLocalPlayerShadowDisposition
.ProvenShapeless));
var sink = new RuntimePlacementPresentationSink(
Runtime,
new RuntimeWorldTransitState(),
WorldState,
new WorldEvents(),
new EntityEffectPoseRegistry(),
new LocalPlayerShadowState(),
() => playerGuid,
_ => { },
[
(record, visible) =>
{
VisibilityEdges.Add((record, visible));
if (VisibilityFailuresRemaining > 0)
{
VisibilityFailuresRemaining--;
throw new InvalidOperationException(
"fixture presentation attach failure");
}
},
]);
Subscription = new AcDream.Runtime.Physics
.RuntimePlacementProjectionSubscription(
EntityObjects.Placements,
static () => new AcDream.Runtime.RuntimeGenerationToken(1UL),
sink);
Materializer = new HostMaterializer(Runtime);
var identity = new LocalPlayerIdentityState
{
ServerGuid = playerGuid,
};
var dormant = new DormantLiveEntityStore();
var teardown = new NoopTeardown();
var deletion = new LiveEntityDeletionController(
Runtime,
EntityObjects,
teardown,
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);
}
public void Dispose()
{
try
{
Runtime.Clear();
}
catch
{
// Failure-path tests assert their own exceptions.
}
}
}
/// <summary>
/// Mirrors the production materializer
/// (DatLiveEntityProjectionMaterializer.MaterializeProjection): route-1
/// world creates materialize residence-managed and self-project only when
/// the committed cell already exists with no active residence.
/// </summary>
private sealed class HostMaterializer(LiveEntityRuntime runtime)
: ILiveEntityProjectionMaterializer
{
internal Action<LiveEntityRecord>? AfterMaterialize { get; set; }
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;
}
AfterMaterialize?.Invoke(record);
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 SphereCollisionSource(float sphereOriginZ = 0f)
: 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>
.Loaded(new FlatSetupCollision(
System.Collections.Immutable.ImmutableArray<
FlatCollisionCylinder>.Empty,
[new FlatCollisionSphere(
new Vector3(0f, 0f, sphereOriginZ),
0.48f)],
height: 0f,
radius: 0f,
stepUpHeight: 0.4f,
stepDownHeight: 0.4f));
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()
{
}
}
}