refactor(app): key live projections by runtime identity
Move materialized live-object sidecars and presentation worksets to exact RuntimeEntityKey ownership. Runtime remains the only GUID/incarnation/local-ID authority while hydration, animation, effects, lights, equipped children, renderer resources, visibility, liveness, and teardown resolve exact projection identities. Preserve synchronous callbacks, local-ID allocation order, and current rendering behavior.
This commit is contained in:
parent
e18df84437
commit
420e5eea70
73 changed files with 2939 additions and 1715 deletions
87
tests/AcDream.App.Tests/World/LiveEntityTestFixture.cs
Normal file
87
tests/AcDream.App.Tests/World/LiveEntityTestFixture.cs
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
using System.Numerics;
|
||||
using AcDream.Core.Net;
|
||||
using AcDream.Core.World;
|
||||
using AcDream.Runtime.Entities;
|
||||
|
||||
namespace AcDream.App.World;
|
||||
|
||||
/// <summary>
|
||||
/// Test-only construction seam for exact Runtime identities and App
|
||||
/// projections. Component fixtures must not manufacture detached
|
||||
/// <see cref="LiveEntityRecord"/> instances because that bypasses the same
|
||||
/// local-ID/incarnation key used by production.
|
||||
/// </summary>
|
||||
internal static class LiveEntityTestFixture
|
||||
{
|
||||
public static LiveEntityRecord CreateExactProjectionRecord(
|
||||
WorldSession.EntitySpawn spawn)
|
||||
{
|
||||
var directory = new RuntimeEntityDirectory();
|
||||
RuntimeEntityRecord canonical = directory.AddActive(spawn);
|
||||
directory.ClaimLocalId(canonical);
|
||||
var projections = new LiveEntityProjectionStore(directory);
|
||||
return projections.AddMaterializing(canonical);
|
||||
}
|
||||
|
||||
public static LiveEntityRecord RegisterAndMaterializeProjection(
|
||||
this LiveEntityRuntime runtime,
|
||||
WorldSession.EntitySpawn spawn,
|
||||
Func<uint, WorldEntity>? factory = null,
|
||||
LiveEntityProjectionKind projectionKind = LiveEntityProjectionKind.World,
|
||||
Action<LiveEntityRecord>? initializeProjection = null)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(runtime);
|
||||
|
||||
LiveEntityRegistrationResult registration =
|
||||
runtime.RegisterLiveEntity(spawn);
|
||||
RuntimeEntityRecord canonical = registration.Canonical
|
||||
?? throw new InvalidOperationException(
|
||||
"The fixture cannot materialize a stale CreateObject.");
|
||||
if (registration.Projection is { } existing)
|
||||
return existing;
|
||||
|
||||
WorldEntity? entity = runtime.MaterializeLiveEntity(
|
||||
canonical,
|
||||
spawn.Position?.LandblockId ?? canonical.FullCellId,
|
||||
factory ?? (id => CreateWorldEntity(id, spawn)),
|
||||
projectionKind,
|
||||
initializeProjection,
|
||||
out LiveEntityRecord? record);
|
||||
if (entity is null || record is null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"The fixture failed to materialize the exact Runtime incarnation.");
|
||||
}
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
private static WorldEntity CreateWorldEntity(
|
||||
uint localEntityId,
|
||||
WorldSession.EntitySpawn spawn)
|
||||
{
|
||||
var position = spawn.Position;
|
||||
return new WorldEntity
|
||||
{
|
||||
Id = localEntityId,
|
||||
ServerGuid = spawn.Guid,
|
||||
SourceGfxObjOrSetupId = spawn.SetupTableId ?? 0u,
|
||||
Position = position is { } placed
|
||||
? new Vector3(
|
||||
placed.PositionX,
|
||||
placed.PositionY,
|
||||
placed.PositionZ)
|
||||
: Vector3.Zero,
|
||||
Rotation = position is { } oriented
|
||||
? new Quaternion(
|
||||
oriented.RotationX,
|
||||
oriented.RotationY,
|
||||
oriented.RotationZ,
|
||||
oriented.RotationW)
|
||||
: Quaternion.Identity,
|
||||
MeshRefs = Array.Empty<MeshRef>(),
|
||||
ParentCellId = position?.LandblockId,
|
||||
EffectCellId = position?.LandblockId,
|
||||
};
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue