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
|
|
@ -17,7 +17,7 @@ public sealed class LiveEntityInboundAuthorityGateTests
|
|||
public void Motion_StrictFreshnessAndWrapAreOwnedBeforePresentation()
|
||||
{
|
||||
LiveEntityRuntime runtime = Runtime();
|
||||
runtime.RegisterLiveEntity(Spawn(Guid, instance: 7, movement: 0xFFFE));
|
||||
Register(runtime, Spawn(Guid, instance: 7, movement: 0xFFFE));
|
||||
var published = new List<AcceptedPhysicsTimestamps>();
|
||||
var gate = new LiveEntityInboundAuthorityGate(
|
||||
runtime,
|
||||
|
|
@ -52,7 +52,7 @@ public sealed class LiveEntityInboundAuthorityGateTests
|
|||
public void AutonomousLocalMotion_ConsumesTimestampButDoesNotPublishPayload()
|
||||
{
|
||||
LiveEntityRuntime runtime = Runtime();
|
||||
runtime.RegisterLiveEntity(Spawn(Guid, instance: 1));
|
||||
Register(runtime, Spawn(Guid, instance: 1));
|
||||
int publishCount = 0;
|
||||
var gate = new LiveEntityInboundAuthorityGate(runtime, (_, _) => publishCount++);
|
||||
|
||||
|
|
@ -72,7 +72,7 @@ public sealed class LiveEntityInboundAuthorityGateTests
|
|||
public void Vector_InvalidPayloadDoesNotConsumeSequenceAndDuplicateIsRejected()
|
||||
{
|
||||
LiveEntityRuntime runtime = Runtime();
|
||||
runtime.RegisterLiveEntity(Spawn(Guid, instance: 2));
|
||||
Register(runtime, Spawn(Guid, instance: 2));
|
||||
var gate = new LiveEntityInboundAuthorityGate(runtime, (_, _) => { });
|
||||
var update = new VectorUpdate.Parsed(
|
||||
Guid,
|
||||
|
|
@ -94,7 +94,7 @@ public sealed class LiveEntityInboundAuthorityGateTests
|
|||
public void Vector_WrappedSequenceIsAccepted()
|
||||
{
|
||||
LiveEntityRuntime runtime = Runtime();
|
||||
runtime.RegisterLiveEntity(Spawn(Guid, instance: 2, vector: 0xFFFE));
|
||||
Register(runtime, Spawn(Guid, instance: 2, vector: 0xFFFE));
|
||||
var gate = new LiveEntityInboundAuthorityGate(runtime, (_, _) => { });
|
||||
|
||||
Assert.True(gate.TryAcceptVector(
|
||||
|
|
@ -112,7 +112,7 @@ public sealed class LiveEntityInboundAuthorityGateTests
|
|||
public void State_EqualIsRejectedAndWrappedSequenceIsAccepted()
|
||||
{
|
||||
LiveEntityRuntime runtime = Runtime();
|
||||
runtime.RegisterLiveEntity(Spawn(Guid, instance: 3, state: 0xFFFE));
|
||||
Register(runtime, Spawn(Guid, instance: 3, state: 0xFFFE));
|
||||
var gate = new LiveEntityInboundAuthorityGate(runtime, (_, _) => { });
|
||||
|
||||
Assert.False(gate.TryAcceptState(
|
||||
|
|
@ -149,7 +149,7 @@ public sealed class LiveEntityInboundAuthorityGateTests
|
|||
Assert.Equal(0xAABB0001u, gate.LastLivePlayerLandblockId);
|
||||
Assert.Equal(0, publishCount);
|
||||
|
||||
runtime.RegisterLiveEntity(Spawn(Guid, instance: 4, position: 1));
|
||||
Register(runtime, Spawn(Guid, instance: 4, position: 1));
|
||||
Assert.True(gate.TryAcceptPosition(
|
||||
update,
|
||||
Guid,
|
||||
|
|
@ -169,7 +169,7 @@ public sealed class LiveEntityInboundAuthorityGateTests
|
|||
public void Position_InvalidPayloadDoesNotConsumeSequence()
|
||||
{
|
||||
LiveEntityRuntime runtime = Runtime();
|
||||
runtime.RegisterLiveEntity(Spawn(Guid, instance: 5, position: 1));
|
||||
Register(runtime, Spawn(Guid, instance: 5, position: 1));
|
||||
var gate = new LiveEntityInboundAuthorityGate(runtime, (_, _) => { });
|
||||
WorldSession.EntityPositionUpdate update = Position(Guid, 5, 2, 0x01010001u);
|
||||
|
||||
|
|
@ -185,7 +185,7 @@ public sealed class LiveEntityInboundAuthorityGateTests
|
|||
public void Position_WrappedSequenceIsAccepted()
|
||||
{
|
||||
LiveEntityRuntime runtime = Runtime();
|
||||
runtime.RegisterLiveEntity(Spawn(Guid, instance: 5, position: 0xFFFE));
|
||||
Register(runtime, Spawn(Guid, instance: 5, position: 0xFFFE));
|
||||
var gate = new LiveEntityInboundAuthorityGate(runtime, (_, _) => { });
|
||||
|
||||
Assert.True(gate.TryAcceptPosition(
|
||||
|
|
@ -201,7 +201,7 @@ public sealed class LiveEntityInboundAuthorityGateTests
|
|||
public void Vector_NewerSameIncarnationPacketInvalidatesCapturedAuthority()
|
||||
{
|
||||
LiveEntityRuntime runtime = Runtime();
|
||||
runtime.RegisterLiveEntity(Spawn(Guid, instance: 5, vector: 1));
|
||||
Register(runtime, Spawn(Guid, instance: 5, vector: 1));
|
||||
var gate = new LiveEntityInboundAuthorityGate(runtime, (_, _) => { });
|
||||
Assert.True(gate.TryAcceptVector(
|
||||
new VectorUpdate.Parsed(Guid, Vector3.One, Vector3.Zero, 5, 2),
|
||||
|
|
@ -220,7 +220,7 @@ public sealed class LiveEntityInboundAuthorityGateTests
|
|||
public void State_NewerSameIncarnationPacketInvalidatesCapturedAuthority()
|
||||
{
|
||||
LiveEntityRuntime runtime = Runtime();
|
||||
runtime.RegisterLiveEntity(Spawn(Guid, instance: 5, state: 1));
|
||||
Register(runtime, Spawn(Guid, instance: 5, state: 1));
|
||||
var gate = new LiveEntityInboundAuthorityGate(runtime, (_, _) => { });
|
||||
Assert.True(gate.TryAcceptState(
|
||||
new SetState.Parsed(Guid, (uint)PhysicsStateFlags.Hidden, 5, 2),
|
||||
|
|
@ -238,7 +238,7 @@ public sealed class LiveEntityInboundAuthorityGateTests
|
|||
public void Motion_PublisherReplacementInvalidatesCapturedIncarnation()
|
||||
{
|
||||
LiveEntityRuntime runtime = Runtime();
|
||||
runtime.RegisterLiveEntity(Spawn(Guid, instance: 6));
|
||||
Register(runtime, Spawn(Guid, instance: 6));
|
||||
var gate = new LiveEntityInboundAuthorityGate(
|
||||
runtime,
|
||||
(_, _) => runtime.RegisterLiveEntity(Spawn(Guid, instance: 7)));
|
||||
|
|
@ -249,15 +249,17 @@ public sealed class LiveEntityInboundAuthorityGateTests
|
|||
out _,
|
||||
out bool timestampAccepted));
|
||||
Assert.True(timestampAccepted);
|
||||
Assert.True(runtime.TryGetRecord(Guid, out LiveEntityRecord replacement));
|
||||
Assert.Equal((ushort)7, replacement.Generation);
|
||||
Assert.True(runtime.TryGetCanonical(Guid, out RuntimeEntityRecord replacement));
|
||||
Assert.Equal((ushort)7, replacement.Incarnation);
|
||||
Assert.Null(replacement.LocalEntityId);
|
||||
Assert.False(runtime.TryGetRecord(Guid, out _));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Position_PublisherNewerChannelInvalidatesCapturedAuthority()
|
||||
{
|
||||
LiveEntityRuntime runtime = Runtime();
|
||||
runtime.RegisterLiveEntity(Spawn(Guid, instance: 8, position: 1));
|
||||
Register(runtime, Spawn(Guid, instance: 8, position: 1));
|
||||
var nested = Position(Guid, 8, 3, 0x01010002u);
|
||||
LiveEntityInboundAuthorityGate? gate = null;
|
||||
gate = new LiveEntityInboundAuthorityGate(
|
||||
|
|
@ -286,7 +288,7 @@ public sealed class LiveEntityInboundAuthorityGateTests
|
|||
public void Position_PublisherNewerVectorPreservesIndependentPositionAuthority()
|
||||
{
|
||||
LiveEntityRuntime runtime = Runtime();
|
||||
runtime.RegisterLiveEntity(Spawn(Guid, instance: 9, position: 1, vector: 1));
|
||||
Register(runtime, Spawn(Guid, instance: 9, position: 1, vector: 1));
|
||||
var gate = new LiveEntityInboundAuthorityGate(
|
||||
runtime,
|
||||
(_, _) => runtime.TryApplyVector(
|
||||
|
|
@ -317,6 +319,11 @@ public sealed class LiveEntityInboundAuthorityGateTests
|
|||
new GpuWorldState(),
|
||||
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }));
|
||||
|
||||
private static LiveEntityRecord Register(
|
||||
LiveEntityRuntime runtime,
|
||||
WorldSession.EntitySpawn spawn) =>
|
||||
runtime.RegisterAndMaterializeProjection(spawn);
|
||||
|
||||
private static WorldSession.EntityMotionUpdate Motion(
|
||||
ushort instance,
|
||||
ushort movement,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue