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
|
|
@ -20,7 +20,7 @@ public sealed class AttachmentUpdateOrderTests
|
|||
var calls = new List<uint>();
|
||||
|
||||
var children = insertionOrder.ToDictionary(id => id, id => parents[id]);
|
||||
new AttachmentUpdateOrder<uint?>().ForEachParentFirst(
|
||||
new AttachmentUpdateOrder<uint, uint?>().ForEachParentFirst(
|
||||
children,
|
||||
static parentId => parentId,
|
||||
id =>
|
||||
|
|
@ -44,7 +44,7 @@ public sealed class AttachmentUpdateOrderTests
|
|||
};
|
||||
var calls = new List<uint>();
|
||||
|
||||
IReadOnlyList<uint> failed = new AttachmentUpdateOrder<uint?>().ForEachParentFirst(
|
||||
IReadOnlyList<uint> failed = new AttachmentUpdateOrder<uint, uint?>().ForEachParentFirst(
|
||||
children,
|
||||
static parentId => parentId,
|
||||
id =>
|
||||
|
|
@ -128,7 +128,7 @@ public sealed class AttachmentUpdateOrderTests
|
|||
[20u] = 10u,
|
||||
[30u] = 20u,
|
||||
};
|
||||
var order = new AttachmentUpdateOrder<uint?>().CollectSubtreePostOrder(
|
||||
var order = new AttachmentUpdateOrder<uint, uint?>().CollectSubtreePostOrder(
|
||||
children,
|
||||
10u,
|
||||
static parentId => parentId);
|
||||
|
|
@ -146,7 +146,7 @@ public sealed class AttachmentUpdateOrderTests
|
|||
};
|
||||
var realized = new List<uint>();
|
||||
|
||||
new AttachmentUpdateOrder<uint?>().RealizeDescendants(
|
||||
new AttachmentUpdateOrder<uint, uint?>().RealizeDescendants(
|
||||
10u,
|
||||
parent => waitingByParent.TryGetValue(parent, out var waiting)
|
||||
? waiting
|
||||
|
|
@ -170,7 +170,7 @@ public sealed class AttachmentUpdateOrderTests
|
|||
};
|
||||
var attempted = new List<uint>();
|
||||
|
||||
new AttachmentUpdateOrder<uint?>().RealizeDescendants(
|
||||
new AttachmentUpdateOrder<uint, uint?>().RealizeDescendants(
|
||||
10u,
|
||||
parent => waitingByParent.TryGetValue(parent, out var waiting)
|
||||
? waiting
|
||||
|
|
|
|||
|
|
@ -106,8 +106,8 @@ public sealed class EquippedChildProjectionWithdrawalTests
|
|||
LiveEntityProjectionKind.Attached);
|
||||
fixture.InstallAttached(parent, oldChild);
|
||||
|
||||
LiveEntityRecord replacement = fixture.Live.RegisterLiveEntity(
|
||||
ControllerFixture.SpawnData(0x70000201u, generation: 2)).Record!;
|
||||
LiveEntityRecord replacement = fixture.Live.RegisterAndMaterializeProjection(
|
||||
ControllerFixture.SpawnData(0x70000201u, generation: 2));
|
||||
|
||||
Assert.Empty(fixture.Controller.AttachedEntityIds);
|
||||
Assert.True(fixture.Live.TryGetRecord(0x70000201u, out LiveEntityRecord current));
|
||||
|
|
@ -136,7 +136,7 @@ public sealed class EquippedChildProjectionWithdrawalTests
|
|||
fixture.Controller.ProjectionRemoved -= Throw;
|
||||
Assert.Equal(1, fixture.Live.RetryPendingTeardowns());
|
||||
|
||||
static void Throw(uint _) =>
|
||||
static void Throw(LiveEntityRecord _) =>
|
||||
throw new InvalidOperationException("injected projection observer failure");
|
||||
}
|
||||
|
||||
|
|
@ -424,11 +424,11 @@ public sealed class EquippedChildProjectionWithdrawalTests
|
|||
fixture.Controller.OnParentEvent(new ParentEvent.Parsed(
|
||||
invalidParent.ServerGuid, childGuid, 1, 0, 1, 2));
|
||||
|
||||
LiveEntityRecord child = fixture.RegisterOnly(
|
||||
RuntimeEntityRecord childIdentity = fixture.RegisterOnly(
|
||||
childGuid,
|
||||
generation: 1,
|
||||
hasPosition: true);
|
||||
fixture.Materialize(child);
|
||||
LiveEntityRecord child = fixture.Materialize(childIdentity);
|
||||
Assert.True(fixture.Live.TryGetSnapshot(
|
||||
childGuid,
|
||||
out WorldSession.EntitySpawn childSpawn));
|
||||
|
|
@ -455,7 +455,7 @@ public sealed class EquippedChildProjectionWithdrawalTests
|
|||
ExactProjectionWithdrawalDisposition.Completed,
|
||||
Failure: null));
|
||||
LiveEntityRecord parent = fixture.Spawn(0x70000254u, generation: 1);
|
||||
LiveEntityRecord child = fixture.RegisterOnly(
|
||||
RuntimeEntityRecord child = fixture.RegisterOnly(
|
||||
0x70000255u,
|
||||
generation: 1,
|
||||
hasPosition: false);
|
||||
|
|
@ -475,7 +475,7 @@ public sealed class EquippedChildProjectionWithdrawalTests
|
|||
out WorldSession.EntitySpawn snapshot));
|
||||
Assert.Equal(parent.ServerGuid, snapshot.ParentGuid);
|
||||
Assert.Null(snapshot.Position);
|
||||
Assert.Null(child.WorldEntity);
|
||||
Assert.False(fixture.Live.TryGetRecord(child.ServerGuid, out _));
|
||||
var relation = new ParentAttachmentRelation(
|
||||
parent.ServerGuid,
|
||||
child.ServerGuid,
|
||||
|
|
@ -490,9 +490,14 @@ public sealed class EquippedChildProjectionWithdrawalTests
|
|||
Array.Empty<Matrix4x4>());
|
||||
fixture.Controller.OnPosePublished(parent.ServerGuid);
|
||||
|
||||
Assert.NotNull(child.WorldEntity);
|
||||
Assert.True(child.IsSpatiallyProjected);
|
||||
Assert.Equal(LiveEntityProjectionKind.Attached, child.ProjectionKind);
|
||||
Assert.True(fixture.Live.TryGetRecord(
|
||||
child.ServerGuid,
|
||||
out LiveEntityRecord childProjection));
|
||||
Assert.NotNull(childProjection.WorldEntity);
|
||||
Assert.True(childProjection.IsSpatiallyProjected);
|
||||
Assert.Equal(
|
||||
LiveEntityProjectionKind.Attached,
|
||||
childProjection.ProjectionKind);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -513,13 +518,12 @@ public sealed class EquippedChildProjectionWithdrawalTests
|
|||
PlacementId = null,
|
||||
PositionSequence = 0,
|
||||
};
|
||||
LiveEntityRecord child = fixture.Live.RegisterLiveEntity(childSpawn).Record!;
|
||||
|
||||
fixture.Live.RegisterLiveEntity(childSpawn);
|
||||
fixture.Controller.OnSpawn(childSpawn);
|
||||
|
||||
var expected = new ParentAttachmentRelation(
|
||||
parent.ServerGuid,
|
||||
child.ServerGuid,
|
||||
childSpawn.Guid,
|
||||
ParentLocation: 0,
|
||||
PlacementId: 0,
|
||||
ParentInstanceSequence: 0,
|
||||
|
|
@ -527,6 +531,9 @@ public sealed class EquippedChildProjectionWithdrawalTests
|
|||
Assert.True(fixture.Live.ParentAttachments.IsCommitted(expected));
|
||||
fixture.Poses.Publish(parent.WorldEntity!, Array.Empty<Matrix4x4>());
|
||||
fixture.Controller.OnPosePublished(parent.ServerGuid);
|
||||
Assert.True(fixture.Live.TryGetRecord(
|
||||
childSpawn.Guid,
|
||||
out LiveEntityRecord child));
|
||||
Assert.Equal(LiveEntityProjectionKind.Attached, child.ProjectionKind);
|
||||
Assert.NotNull(child.WorldEntity);
|
||||
}
|
||||
|
|
@ -560,10 +567,13 @@ public sealed class EquippedChildProjectionWithdrawalTests
|
|||
PlacementId = 0,
|
||||
PositionSequence = 0,
|
||||
};
|
||||
LiveEntityRecord child = fixture.Live.RegisterLiveEntity(childSpawn).Record!;
|
||||
fixture.Live.RegisterLiveEntity(childSpawn);
|
||||
fixture.Controller.OnSpawn(childSpawn);
|
||||
fixture.Poses.Publish(parent.WorldEntity!, Array.Empty<Matrix4x4>());
|
||||
fixture.Controller.OnPosePublished(parent.ServerGuid);
|
||||
Assert.True(fixture.Live.TryGetRecord(
|
||||
childSpawn.Guid,
|
||||
out LiveEntityRecord child));
|
||||
WorldEntity entity = child.WorldEntity!;
|
||||
Assert.Null(entity.PaletteOverride);
|
||||
WorldSession.EntitySpawn grandchildSpawn = ControllerFixture.SpawnData(
|
||||
|
|
@ -576,9 +586,11 @@ public sealed class EquippedChildProjectionWithdrawalTests
|
|||
PlacementId = 0,
|
||||
PositionSequence = 0,
|
||||
};
|
||||
LiveEntityRecord grandchild = fixture.Live.RegisterLiveEntity(
|
||||
grandchildSpawn).Record!;
|
||||
fixture.Live.RegisterLiveEntity(grandchildSpawn);
|
||||
fixture.Controller.OnSpawn(grandchildSpawn);
|
||||
Assert.True(fixture.Live.TryGetRecord(
|
||||
grandchildSpawn.Guid,
|
||||
out LiveEntityRecord grandchild));
|
||||
WorldEntity grandchildEntity = grandchild.WorldEntity!;
|
||||
Assert.Equal(
|
||||
LiveEntityProjectionKind.Attached,
|
||||
|
|
@ -642,12 +654,12 @@ public sealed class EquippedChildProjectionWithdrawalTests
|
|||
using (fixture)
|
||||
{
|
||||
LiveEntityRecord parent = fixture.Spawn(0x7000025Cu, generation: 1);
|
||||
LiveEntityRecord child = fixture.RegisterOnly(
|
||||
RuntimeEntityRecord childIdentity = fixture.RegisterOnly(
|
||||
0x7000025Du,
|
||||
generation: 1,
|
||||
hasPosition: true,
|
||||
hasSetup: false);
|
||||
fixture.Materialize(child);
|
||||
LiveEntityRecord child = fixture.Materialize(childIdentity);
|
||||
child.HasPartArray = false;
|
||||
var update = new ParentEvent.Parsed(
|
||||
parent.ServerGuid, child.ServerGuid, 0, 0, 1, 1);
|
||||
|
|
@ -763,7 +775,7 @@ public sealed class EquippedChildProjectionWithdrawalTests
|
|||
0x70000257u,
|
||||
generation: 1,
|
||||
LiveEntityProjectionKind.Attached);
|
||||
LiveEntityRecord waitingParent = fixture.RegisterOnly(
|
||||
RuntimeEntityRecord waitingParent = fixture.RegisterOnly(
|
||||
0x70000258u,
|
||||
generation: 1,
|
||||
hasPosition: true);
|
||||
|
|
@ -1117,7 +1129,8 @@ public sealed class EquippedChildProjectionWithdrawalTests
|
|||
}
|
||||
}
|
||||
|
||||
private static LiveEntityRecord ChildRecord() => new(
|
||||
private static LiveEntityRecord ChildRecord() =>
|
||||
LiveEntityTestFixture.CreateExactProjectionRecord(
|
||||
new WorldSession.EntitySpawn(
|
||||
0x70000100u,
|
||||
new CreateObject.ServerPosition(
|
||||
|
|
@ -1188,12 +1201,12 @@ public sealed class EquippedChildProjectionWithdrawalTests
|
|||
ushort generation,
|
||||
LiveEntityProjectionKind kind = LiveEntityProjectionKind.World)
|
||||
{
|
||||
LiveEntityRecord record = RegisterOnly(guid, generation, hasPosition: true);
|
||||
Materialize(record, kind);
|
||||
return record;
|
||||
RuntimeEntityRecord canonical =
|
||||
RegisterOnly(guid, generation, hasPosition: true);
|
||||
return Materialize(canonical, kind);
|
||||
}
|
||||
|
||||
internal LiveEntityRecord RegisterOnly(
|
||||
internal RuntimeEntityRecord RegisterOnly(
|
||||
uint guid,
|
||||
ushort generation,
|
||||
bool hasPosition,
|
||||
|
|
@ -1204,28 +1217,35 @@ public sealed class EquippedChildProjectionWithdrawalTests
|
|||
spawn = spawn with { Position = null };
|
||||
if (!hasSetup)
|
||||
spawn = spawn with { SetupTableId = null };
|
||||
return Live.RegisterLiveEntity(spawn).Record!;
|
||||
return Assert.IsType<RuntimeEntityRecord>(
|
||||
Live.RegisterLiveEntity(spawn).Canonical);
|
||||
}
|
||||
|
||||
internal void Materialize(
|
||||
LiveEntityRecord record,
|
||||
internal LiveEntityRecord Materialize(
|
||||
RuntimeEntityRecord canonical,
|
||||
LiveEntityProjectionKind kind = LiveEntityProjectionKind.World)
|
||||
{
|
||||
Live.MaterializeLiveEntity(
|
||||
record.ServerGuid,
|
||||
WorldEntity? entity = Live.MaterializeLiveEntity(
|
||||
canonical,
|
||||
Cell,
|
||||
id => new WorldEntity
|
||||
{
|
||||
Id = id,
|
||||
ServerGuid = record.ServerGuid,
|
||||
ServerGuid = canonical.ServerGuid,
|
||||
SourceGfxObjOrSetupId = 0x02000001u,
|
||||
Position = Vector3.Zero,
|
||||
Rotation = Quaternion.Identity,
|
||||
MeshRefs = Array.Empty<MeshRef>(),
|
||||
ParentCellId = Cell,
|
||||
},
|
||||
kind);
|
||||
kind,
|
||||
initializeProjection: null,
|
||||
out LiveEntityRecord? projected);
|
||||
Assert.NotNull(entity);
|
||||
LiveEntityRecord record =
|
||||
Assert.IsType<LiveEntityRecord>(projected);
|
||||
record.HasPartArray = true;
|
||||
return record;
|
||||
}
|
||||
|
||||
internal static WorldSession.EntitySpawn SpawnData(uint guid, ushort generation) => new(
|
||||
|
|
@ -1277,7 +1297,7 @@ public sealed class EquippedChildProjectionWithdrawalTests
|
|||
"_attachedByChild",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic)!;
|
||||
var map = (IDictionary)mapField.GetValue(Controller)!;
|
||||
map.Add(child.ServerGuid, attached);
|
||||
map.Add(child.ProjectionKey!.Value, attached);
|
||||
}
|
||||
|
||||
internal void CommitRenderedRelation(ParentAttachmentRelation relation)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public sealed class LiveAppearanceAnimationTests
|
|||
var runtime = new AcDream.App.World.LiveEntityRuntime(
|
||||
new AcDream.App.Streaming.GpuWorldState(),
|
||||
new AcDream.App.World.DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }));
|
||||
var record = runtime.RegisterLiveEntity(new AcDream.Core.Net.WorldSession.EntitySpawn(
|
||||
var spawn = new AcDream.Core.Net.WorldSession.EntitySpawn(
|
||||
guid,
|
||||
Position: null,
|
||||
SetupTableId: null,
|
||||
|
|
@ -33,8 +33,11 @@ public sealed class LiveAppearanceAnimationTests
|
|||
ItemType: null,
|
||||
MotionState: null,
|
||||
MotionTableId: null,
|
||||
InstanceSequence: 1)).Record!;
|
||||
WorldEntity entity = Entity(0x70000002u, 0x01000001u);
|
||||
InstanceSequence: 1);
|
||||
LiveEntityRecord record = runtime.RegisterAndMaterializeProjection(
|
||||
spawn,
|
||||
id => Entity(id, 0x01000001u, guid));
|
||||
WorldEntity entity = Assert.IsType<WorldEntity>(record.WorldEntity);
|
||||
var state = new LiveEntityAnimationState
|
||||
{
|
||||
Entity = entity,
|
||||
|
|
@ -47,7 +50,6 @@ public sealed class LiveAppearanceAnimationTests
|
|||
PartTemplate = Array.Empty<LiveAnimationPartTemplate>(),
|
||||
PartAvailability = Array.Empty<bool>(),
|
||||
};
|
||||
record.WorldEntity = entity;
|
||||
record.AnimationRuntime = state;
|
||||
|
||||
LiveEntityAppearanceUpdateState captured = Assert.IsType<LiveEntityAppearanceUpdateState>(
|
||||
|
|
@ -188,10 +190,13 @@ public sealed class LiveAppearanceAnimationTests
|
|||
MotionTableId: null,
|
||||
InstanceSequence: instance);
|
||||
|
||||
private static WorldEntity Entity(uint id, uint gfxObjId) => new()
|
||||
private static WorldEntity Entity(
|
||||
uint id,
|
||||
uint gfxObjId,
|
||||
uint serverGuid = 0x50000001u) => new()
|
||||
{
|
||||
Id = id,
|
||||
ServerGuid = 0x50000001u,
|
||||
ServerGuid = serverGuid,
|
||||
SourceGfxObjOrSetupId = 0x02000001u,
|
||||
Position = Vector3.Zero,
|
||||
Rotation = Quaternion.Identity,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using AcDream.Core.Net;
|
|||
using AcDream.Core.Net.Messages;
|
||||
using AcDream.Core.Physics;
|
||||
using AcDream.Core.World;
|
||||
using AcDream.Runtime.Entities;
|
||||
using DatReaderWriter.DBObjs;
|
||||
using DatReaderWriter.Types;
|
||||
|
||||
|
|
@ -64,9 +65,9 @@ public sealed class LiveEntityAnimationPresenterTests
|
|||
old.Live.SetAnimationRuntime(Guid, replacement);
|
||||
var presenter = Presenter(old.Live, new EntityEffectPoseRegistry(), new Context());
|
||||
|
||||
presenter.Present(new Dictionary<uint, LiveEntityAnimationSchedule>
|
||||
presenter.Present(new Dictionary<RuntimeEntityKey, LiveEntityAnimationSchedule>
|
||||
{
|
||||
[old.Entity.Id] = stale,
|
||||
[old.Record.ProjectionKey!.Value] = stale,
|
||||
});
|
||||
|
||||
Assert.Empty(replacement.MeshRefsScratch);
|
||||
|
|
@ -178,9 +179,9 @@ public sealed class LiveEntityAnimationPresenterTests
|
|||
[true]);
|
||||
var presenter = Presenter(fixture.Live, new EntityEffectPoseRegistry(), new Context());
|
||||
|
||||
presenter.Present(new Dictionary<uint, LiveEntityAnimationSchedule>
|
||||
presenter.Present(new Dictionary<RuntimeEntityKey, LiveEntityAnimationSchedule>
|
||||
{
|
||||
[fixture.Entity.Id] = stale,
|
||||
[fixture.Record.ProjectionKey!.Value] = stale,
|
||||
});
|
||||
|
||||
Assert.Empty(fixture.State.MeshRefsScratch);
|
||||
|
|
@ -252,11 +253,11 @@ public sealed class LiveEntityAnimationPresenterTests
|
|||
Assert.Equal(2, nested.Count);
|
||||
};
|
||||
var presenter = Presenter(first.Live, poses, new Context());
|
||||
var schedules = new Dictionary<uint, LiveEntityAnimationSchedule>
|
||||
var schedules = new Dictionary<RuntimeEntityKey, LiveEntityAnimationSchedule>
|
||||
{
|
||||
[first.Entity.Id] = Schedule(first,
|
||||
[first.Record.ProjectionKey!.Value] = Schedule(first,
|
||||
[new PartTransform(Vector3.UnitX, Quaternion.Identity)]),
|
||||
[second.Entity.Id] = Schedule(second,
|
||||
[second.Record.ProjectionKey!.Value] = Schedule(second,
|
||||
[new PartTransform(Vector3.UnitY, Quaternion.Identity)]),
|
||||
};
|
||||
|
||||
|
|
@ -283,11 +284,11 @@ public sealed class LiveEntityAnimationPresenterTests
|
|||
first.Live.SetAnimationRuntime(Guid + 1, replacement);
|
||||
};
|
||||
var presenter = Presenter(first.Live, poses, new Context());
|
||||
var schedules = new Dictionary<uint, LiveEntityAnimationSchedule>
|
||||
var schedules = new Dictionary<RuntimeEntityKey, LiveEntityAnimationSchedule>
|
||||
{
|
||||
[first.Entity.Id] = Schedule(first,
|
||||
[first.Record.ProjectionKey!.Value] = Schedule(first,
|
||||
[new PartTransform(Vector3.UnitX, Quaternion.Identity)]),
|
||||
[second.Entity.Id] = Schedule(second,
|
||||
[second.Record.ProjectionKey!.Value] = Schedule(second,
|
||||
[new PartTransform(new Vector3(99f, 0f, 0f), Quaternion.Identity)]),
|
||||
};
|
||||
|
||||
|
|
@ -305,11 +306,11 @@ public sealed class LiveEntityAnimationPresenterTests
|
|||
var second = Add(first.Live, Guid + 1, partCount: 1);
|
||||
var poses = new EntityEffectPoseRegistry();
|
||||
var presenter = Presenter(first.Live, poses, new Context());
|
||||
var schedules = new Dictionary<uint, LiveEntityAnimationSchedule>
|
||||
var schedules = new Dictionary<RuntimeEntityKey, LiveEntityAnimationSchedule>
|
||||
{
|
||||
[first.Entity.Id] = Schedule(first,
|
||||
[first.Record.ProjectionKey!.Value] = Schedule(first,
|
||||
[new PartTransform(Vector3.UnitX, Quaternion.Identity)]),
|
||||
[second.Entity.Id] = Schedule(second,
|
||||
[second.Record.ProjectionKey!.Value] = Schedule(second,
|
||||
[new PartTransform(Vector3.UnitY, Quaternion.Identity)]),
|
||||
};
|
||||
bool recursed = false;
|
||||
|
|
@ -359,9 +360,9 @@ public sealed class LiveEntityAnimationPresenterTests
|
|||
fixture.Record.ObjectClockEpoch,
|
||||
fixture.Record.ProjectionMutationVersion,
|
||||
fixture.State.PresentationRevision);
|
||||
var schedules = new Dictionary<uint, LiveEntityAnimationSchedule>
|
||||
var schedules = new Dictionary<RuntimeEntityKey, LiveEntityAnimationSchedule>
|
||||
{
|
||||
[fixture.Entity.Id] = schedule,
|
||||
[fixture.Record.ProjectionKey!.Value] = schedule,
|
||||
};
|
||||
var poses = new EntityEffectPoseRegistry();
|
||||
var presenter = Presenter(fixture.Live, poses, new Context());
|
||||
|
|
@ -407,12 +408,12 @@ public sealed class LiveEntityAnimationPresenterTests
|
|||
}
|
||||
}
|
||||
|
||||
private static IReadOnlyDictionary<uint, LiveEntityAnimationSchedule> Schedules(
|
||||
private static IReadOnlyDictionary<RuntimeEntityKey, LiveEntityAnimationSchedule> Schedules(
|
||||
Fixture fixture,
|
||||
IReadOnlyList<PartTransform> frames) =>
|
||||
new Dictionary<uint, LiveEntityAnimationSchedule>
|
||||
new Dictionary<RuntimeEntityKey, LiveEntityAnimationSchedule>
|
||||
{
|
||||
[fixture.Entity.Id] = Schedule(fixture, frames),
|
||||
[fixture.Record.ProjectionKey!.Value] = Schedule(fixture, frames),
|
||||
};
|
||||
|
||||
private static LiveEntityAnimationSchedule Schedule(
|
||||
|
|
@ -452,10 +453,8 @@ public sealed class LiveEntityAnimationPresenterTests
|
|||
float scale = 1f,
|
||||
bool withSequencer = true)
|
||||
{
|
||||
LiveEntityRecord record = live.RegisterLiveEntity(Spawn(guid)).Record!;
|
||||
WorldEntity entity = live.MaterializeLiveEntity(
|
||||
guid,
|
||||
Cell,
|
||||
LiveEntityRecord record = live.RegisterAndMaterializeProjection(
|
||||
Spawn(guid),
|
||||
id => new WorldEntity
|
||||
{
|
||||
Id = id,
|
||||
|
|
@ -465,7 +464,8 @@ public sealed class LiveEntityAnimationPresenterTests
|
|||
Rotation = Quaternion.Identity,
|
||||
MeshRefs = Array.Empty<MeshRef>(),
|
||||
ParentCellId = Cell,
|
||||
})!;
|
||||
});
|
||||
WorldEntity entity = Assert.IsType<WorldEntity>(record.WorldEntity);
|
||||
LiveEntityAnimationState state = State(entity, partCount, scale, withSequencer);
|
||||
entity.SetIndexedPartPoses(
|
||||
Enumerable.Repeat(Matrix4x4.Identity, partCount).ToArray(),
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ using AcDream.Core.Net.Messages;
|
|||
using AcDream.Core.Physics;
|
||||
using AcDream.Core.World;
|
||||
using AcDream.Core.Vfx;
|
||||
using AcDream.Runtime.Entities;
|
||||
using DatReaderWriter.DBObjs;
|
||||
using DatReaderWriter.Enums;
|
||||
using DatReaderWriter.Types;
|
||||
|
|
@ -36,14 +37,14 @@ public sealed class LiveEntityAnimationSchedulerTests
|
|||
localHiddenPartPoseDirty: true,
|
||||
liveCenterX: 0,
|
||||
liveCenterY: 0)
|
||||
.TryGetValue(animation.Entity.Id, out LiveEntityAnimationSchedule marked));
|
||||
.TryGetValue(record.ProjectionKey!.Value, out LiveEntityAnimationSchedule marked));
|
||||
bool repeated = scheduler.Tick(
|
||||
PhysicsBody.MaxQuantum,
|
||||
animation.Entity.Position,
|
||||
localHiddenPartPoseDirty: false,
|
||||
liveCenterX: 0,
|
||||
liveCenterY: 0)
|
||||
.TryGetValue(animation.Entity.Id, out LiveEntityAnimationSchedule consumed);
|
||||
.TryGetValue(record.ProjectionKey!.Value, out LiveEntityAnimationSchedule consumed);
|
||||
|
||||
Assert.True(marked.ComposeParts);
|
||||
Assert.NotNull(marked.SequenceFrames);
|
||||
|
|
@ -73,14 +74,14 @@ public sealed class LiveEntityAnimationSchedulerTests
|
|||
localHiddenPartPoseDirty: false,
|
||||
liveCenterX: 0,
|
||||
liveCenterY: 0)
|
||||
.TryGetValue(animation.Entity.Id, out LiveEntityAnimationSchedule marked));
|
||||
.TryGetValue(record.ProjectionKey!.Value, out LiveEntityAnimationSchedule marked));
|
||||
bool repeated = scheduler.Tick(
|
||||
elapsedSeconds: 0f,
|
||||
playerPosition: null,
|
||||
localHiddenPartPoseDirty: false,
|
||||
liveCenterX: 0,
|
||||
liveCenterY: 0)
|
||||
.TryGetValue(animation.Entity.Id, out LiveEntityAnimationSchedule consumed);
|
||||
.TryGetValue(record.ProjectionKey!.Value, out LiveEntityAnimationSchedule consumed);
|
||||
|
||||
Assert.True(marked.ComposeParts);
|
||||
Assert.NotNull(marked.SequenceFrames);
|
||||
|
|
@ -91,7 +92,7 @@ public sealed class LiveEntityAnimationSchedulerTests
|
|||
[Fact]
|
||||
public void VisibleAnimationWithoutRemoteMotion_AppliesCompleteRootFrame()
|
||||
{
|
||||
var (live, _, animation) = BuildVisibleAnimatedWithPosFrames(RemoteGuid);
|
||||
var (live, record, animation) = BuildVisibleAnimatedWithPosFrames(RemoteGuid);
|
||||
var retainedBodyOwner = BuildRemote(animation.Entity);
|
||||
retainedBodyOwner.Body.SnapToCell(
|
||||
Cell,
|
||||
|
|
@ -108,7 +109,7 @@ public sealed class LiveEntityAnimationSchedulerTests
|
|||
localHiddenPartPoseDirty: false,
|
||||
liveCenterX: 0,
|
||||
liveCenterY: 0)
|
||||
.ContainsKey(animation.Entity.Id));
|
||||
.ContainsKey(record.ProjectionKey!.Value));
|
||||
|
||||
Assert.True(animation.Entity.Position.X > startX + 1f);
|
||||
}
|
||||
|
|
@ -116,14 +117,14 @@ public sealed class LiveEntityAnimationSchedulerTests
|
|||
[Fact]
|
||||
public void ScheduleOwnsPartFramesAcrossLaterSequencerSampling()
|
||||
{
|
||||
var (live, _, animation) = BuildVisibleAnimatedWithPosFrames(RemoteGuid);
|
||||
var (live, record, animation) = BuildVisibleAnimatedWithPosFrames(RemoteGuid);
|
||||
LiveEntityAnimationScheduler scheduler = BuildScheduler(live, LocalGuid);
|
||||
LiveEntityAnimationSchedule schedule = scheduler.Tick(
|
||||
0.1f,
|
||||
animation.Entity.Position,
|
||||
localHiddenPartPoseDirty: false,
|
||||
liveCenterX: 0,
|
||||
liveCenterY: 0)[animation.Entity.Id];
|
||||
liveCenterY: 0)[record.ProjectionKey!.Value];
|
||||
PartTransform retained = schedule.SequenceFrames![0];
|
||||
animation.CaptureSequenceFrames(
|
||||
[new PartTransform(new Vector3(77f, 76f, 75f), Quaternion.Identity)]);
|
||||
|
|
@ -194,7 +195,7 @@ public sealed class LiveEntityAnimationSchedulerTests
|
|||
liveCenterY: 0);
|
||||
|
||||
Assert.True(entity.Position.X > startX);
|
||||
Assert.Same(record, live.SpatialRootObjects[RemoteGuid]);
|
||||
Assert.True(live.IsCurrentSpatialRootObject(record));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -224,7 +225,7 @@ public sealed class LiveEntityAnimationSchedulerTests
|
|||
|
||||
Assert.True(entity.Position.X > startX + 0.5f);
|
||||
Assert.True(remote.Interp.IsActive || entity.Position.X >= startX + 0.99f);
|
||||
Assert.Same(record, live.SpatialRootObjects[RemoteGuid]);
|
||||
Assert.True(live.IsCurrentSpatialRootObject(record));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -343,14 +344,14 @@ public sealed class LiveEntityAnimationSchedulerTests
|
|||
physics: physics,
|
||||
projectiles: projectiles);
|
||||
|
||||
IReadOnlyDictionary<uint, LiveEntityAnimationSchedule> schedules = scheduler.Tick(
|
||||
IReadOnlyDictionary<RuntimeEntityKey, LiveEntityAnimationSchedule> schedules = scheduler.Tick(
|
||||
0.1f,
|
||||
animation.Entity.Position,
|
||||
localHiddenPartPoseDirty: false,
|
||||
liveCenterX: 1,
|
||||
liveCenterY: 1);
|
||||
|
||||
Assert.Contains(animation.Entity.Id, schedules.Keys);
|
||||
Assert.Contains(record.ProjectionKey!.Value, schedules.Keys);
|
||||
Assert.Equal(1, rootPublishes);
|
||||
float distance = animation.Entity.Position.X - startX;
|
||||
Assert.InRange(distance, 0.79f, 0.81f);
|
||||
|
|
@ -374,7 +375,7 @@ public sealed class LiveEntityAnimationSchedulerTests
|
|||
isLocalPlayer: false);
|
||||
});
|
||||
|
||||
IReadOnlyDictionary<uint, LiveEntityAnimationSchedule> schedules = scheduler.Tick(
|
||||
IReadOnlyDictionary<RuntimeEntityKey, LiveEntityAnimationSchedule> schedules = scheduler.Tick(
|
||||
PhysicsBody.MaxQuantum * 2.5f,
|
||||
animation.Entity.Position,
|
||||
localHiddenPartPoseDirty: false,
|
||||
|
|
@ -407,7 +408,7 @@ public sealed class LiveEntityAnimationSchedulerTests
|
|||
},
|
||||
_ => rootPublishes++);
|
||||
|
||||
IReadOnlyDictionary<uint, LiveEntityAnimationSchedule> schedules = scheduler.Tick(
|
||||
IReadOnlyDictionary<RuntimeEntityKey, LiveEntityAnimationSchedule> schedules = scheduler.Tick(
|
||||
PhysicsBody.MaxQuantum * 2.5f,
|
||||
animation.Entity.Position,
|
||||
localHiddenPartPoseDirty: false,
|
||||
|
|
@ -441,7 +442,7 @@ public sealed class LiveEntityAnimationSchedulerTests
|
|||
},
|
||||
_ => rootPublishes++);
|
||||
|
||||
IReadOnlyDictionary<uint, LiveEntityAnimationSchedule> schedules = scheduler.Tick(
|
||||
IReadOnlyDictionary<RuntimeEntityKey, LiveEntityAnimationSchedule> schedules = scheduler.Tick(
|
||||
PhysicsBody.MaxQuantum * 2.5f,
|
||||
animation.Entity.Position,
|
||||
localHiddenPartPoseDirty: false,
|
||||
|
|
@ -472,7 +473,7 @@ public sealed class LiveEntityAnimationSchedulerTests
|
|||
},
|
||||
_ => rootPublishes++);
|
||||
|
||||
IReadOnlyDictionary<uint, LiveEntityAnimationSchedule> schedules = scheduler.Tick(
|
||||
IReadOnlyDictionary<RuntimeEntityKey, LiveEntityAnimationSchedule> schedules = scheduler.Tick(
|
||||
PhysicsBody.MaxQuantum * 2.5f,
|
||||
animation.Entity.Position,
|
||||
localHiddenPartPoseDirty: false,
|
||||
|
|
@ -509,7 +510,7 @@ public sealed class LiveEntityAnimationSchedulerTests
|
|||
},
|
||||
_ => rootPublishes++);
|
||||
|
||||
IReadOnlyDictionary<uint, LiveEntityAnimationSchedule> schedules = scheduler.Tick(
|
||||
IReadOnlyDictionary<RuntimeEntityKey, LiveEntityAnimationSchedule> schedules = scheduler.Tick(
|
||||
PhysicsBody.MaxQuantum * 2.5f,
|
||||
animation.Entity.Position,
|
||||
localHiddenPartPoseDirty: false,
|
||||
|
|
@ -572,7 +573,7 @@ public sealed class LiveEntityAnimationSchedulerTests
|
|||
_ => throw new InvalidOperationException(),
|
||||
LiveEntityProjectionKind.Attached));
|
||||
Assert.False(record.ObjectClock.IsActive);
|
||||
Assert.DoesNotContain(RemoteGuid, live.SpatialRootObjects.Keys);
|
||||
Assert.False(live.IsCurrentSpatialRootObject(record));
|
||||
|
||||
scheduler.Tick(
|
||||
PhysicsBody.MaxQuantum,
|
||||
|
|
@ -590,7 +591,7 @@ public sealed class LiveEntityAnimationSchedulerTests
|
|||
_ => throw new InvalidOperationException(),
|
||||
LiveEntityProjectionKind.World));
|
||||
Assert.True(record.ObjectClock.IsActive);
|
||||
Assert.Contains(RemoteGuid, live.SpatialRootObjects.Keys);
|
||||
Assert.True(live.IsCurrentSpatialRootObject(record));
|
||||
|
||||
scheduler.Tick(
|
||||
PhysicsBody.MaxQuantum,
|
||||
|
|
@ -634,8 +635,8 @@ public sealed class LiveEntityAnimationSchedulerTests
|
|||
(_, _) => (0.48f, 1.835f));
|
||||
var identity = new LocalPlayerIdentityState { ServerGuid = localPlayerGuid };
|
||||
var poses = new EntityEffectPoseRegistry();
|
||||
foreach (WorldEntity entity in live.MaterializedWorldEntities.Values)
|
||||
poses.PublishMeshRefs(entity);
|
||||
foreach (LiveEntityRecord record in live.MaterializedRecords)
|
||||
poses.PublishMeshRefs(record.WorldEntity!);
|
||||
IAnimationHookCaptureSink animationHooks = captureHooks is null
|
||||
? new AnimationHookCaptureSink(new AnimationHookFrameQueue(
|
||||
new AnimationHookRouter(),
|
||||
|
|
@ -681,10 +682,8 @@ public sealed class LiveEntityAnimationSchedulerTests
|
|||
var live = new LiveEntityRuntime(
|
||||
spatial,
|
||||
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }));
|
||||
LiveEntityRecord record = live.RegisterLiveEntity(Spawn(guid)).Record!;
|
||||
WorldEntity entity = live.MaterializeLiveEntity(
|
||||
guid,
|
||||
Cell,
|
||||
LiveEntityRecord record = live.RegisterAndMaterializeProjection(
|
||||
Spawn(guid),
|
||||
id => new WorldEntity
|
||||
{
|
||||
Id = id,
|
||||
|
|
@ -694,7 +693,8 @@ public sealed class LiveEntityAnimationSchedulerTests
|
|||
Rotation = Quaternion.Identity,
|
||||
MeshRefs = Array.Empty<MeshRef>(),
|
||||
ParentCellId = Cell,
|
||||
})!;
|
||||
});
|
||||
WorldEntity entity = Assert.IsType<WorldEntity>(record.WorldEntity);
|
||||
var setup = new Setup();
|
||||
var animation = new LiveEntityAnimationState
|
||||
{
|
||||
|
|
@ -803,10 +803,8 @@ public sealed class LiveEntityAnimationSchedulerTests
|
|||
var live = new LiveEntityRuntime(
|
||||
spatial,
|
||||
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }));
|
||||
LiveEntityRecord record = live.RegisterLiveEntity(Spawn(guid, state)).Record!;
|
||||
WorldEntity entity = live.MaterializeLiveEntity(
|
||||
guid,
|
||||
Cell,
|
||||
LiveEntityRecord record = live.RegisterAndMaterializeProjection(
|
||||
Spawn(guid, state),
|
||||
id => new WorldEntity
|
||||
{
|
||||
Id = id,
|
||||
|
|
@ -816,7 +814,8 @@ public sealed class LiveEntityAnimationSchedulerTests
|
|||
Rotation = Quaternion.Identity,
|
||||
MeshRefs = Array.Empty<MeshRef>(),
|
||||
ParentCellId = Cell,
|
||||
})!;
|
||||
});
|
||||
WorldEntity entity = Assert.IsType<WorldEntity>(record.WorldEntity);
|
||||
return (live, record, entity);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -294,10 +294,8 @@ public sealed class LiveEntityCreateSupersessionRecoveryTests
|
|||
|
||||
private static LiveEntityRecord RegisterAndMaterialize(LiveEntityRuntime runtime)
|
||||
{
|
||||
LiveEntityRecord record = runtime.RegisterLiveEntity(Spawn()).Record!;
|
||||
runtime.MaterializeLiveEntity(
|
||||
Guid,
|
||||
Cell,
|
||||
LiveEntityRecord record = runtime.RegisterAndMaterializeProjection(
|
||||
Spawn(),
|
||||
id => new WorldEntity
|
||||
{
|
||||
Id = id,
|
||||
|
|
|
|||
|
|
@ -147,8 +147,8 @@ public sealed class LiveRenderProjectionJournalTests
|
|||
incarnation,
|
||||
harness.Journal.Pending[0].Record.OwnerIncarnation);
|
||||
Assert.True(harness.Runtime.WithdrawLiveEntityProjection(Guid));
|
||||
harness.Projections.OnProjectionRemoved(record.WorldEntity.Id);
|
||||
harness.Projections.OnProjectionRemoved(record.WorldEntity.Id);
|
||||
harness.Projections.OnProjectionRemoved(record);
|
||||
harness.Projections.OnProjectionRemoved(record);
|
||||
Assert.Equal(2, harness.Journal.Count);
|
||||
Assert.Equal(
|
||||
RenderProjectionDeltaKind.UpdateFlags,
|
||||
|
|
@ -166,13 +166,10 @@ public sealed class LiveRenderProjectionJournalTests
|
|||
uint firstLocalId = first.WorldEntity!.Id;
|
||||
harness.Journal.DrainTo(harness.Scene);
|
||||
|
||||
LiveEntityRegistrationResult replacement =
|
||||
harness.Runtime.RegisterLiveEntity(Spawn(Guid, instance: 5));
|
||||
LiveEntityRecord second = replacement.Record!;
|
||||
WorldEntity secondEntity = harness.Runtime.MaterializeLiveEntity(
|
||||
Guid,
|
||||
CellId,
|
||||
localId => Entity(localId, Guid))!;
|
||||
LiveEntityRecord second = harness.Runtime.RegisterAndMaterializeProjection(
|
||||
Spawn(Guid, instance: 5),
|
||||
localId => Entity(localId, Guid));
|
||||
WorldEntity secondEntity = Assert.IsType<WorldEntity>(second.WorldEntity);
|
||||
second.InitialHydrationCompleted = true;
|
||||
LiveEntityReadyCandidate current = LiveEntityReadyCandidate.Capture(second);
|
||||
Assert.True(harness.Projections.OnEntityReady(current));
|
||||
|
|
@ -209,7 +206,7 @@ public sealed class LiveRenderProjectionJournalTests
|
|||
|
||||
LiveEntityRegistrationResult duplicate =
|
||||
harness.Runtime.RegisterLiveEntity(Spawn(Guid, instance: 5));
|
||||
Assert.Same(record, duplicate.Record);
|
||||
Assert.Same(record, duplicate.Projection);
|
||||
Assert.True(harness.Projections.OnEntityReady(
|
||||
LiveEntityReadyCandidate.Capture(record)));
|
||||
|
||||
|
|
@ -285,7 +282,7 @@ public sealed class LiveRenderProjectionJournalTests
|
|||
LiveEntityReadyCandidate.Capture(record)));
|
||||
harness.Journal.DrainTo(harness.Scene);
|
||||
Assert.True(harness.Runtime.WithdrawLiveEntityProjection(Guid));
|
||||
harness.Projections.OnProjectionRemoved(record.WorldEntity!.Id);
|
||||
harness.Projections.OnProjectionRemoved(record);
|
||||
harness.Journal.DrainTo(harness.Scene);
|
||||
|
||||
harness.Projections.SynchronizeActiveSources();
|
||||
|
|
@ -311,7 +308,7 @@ public sealed class LiveRenderProjectionJournalTests
|
|||
LiveEntityReadyCandidate.Capture(record)));
|
||||
harness.Journal.DrainTo(harness.Scene);
|
||||
Assert.True(harness.Runtime.WithdrawLiveEntityProjection(Guid));
|
||||
harness.Projections.OnProjectionRemoved(record.WorldEntity!.Id);
|
||||
harness.Projections.OnProjectionRemoved(record);
|
||||
harness.Journal.DrainTo(harness.Scene);
|
||||
Assert.True(harness.Runtime.RebucketLiveEntity(Guid, CellId));
|
||||
|
||||
|
|
@ -337,7 +334,7 @@ public sealed class LiveRenderProjectionJournalTests
|
|||
LiveEntityReadyCandidate.Capture(record)));
|
||||
harness.Journal.DrainTo(harness.Scene);
|
||||
Assert.True(harness.Runtime.WithdrawLiveEntityProjection(Guid));
|
||||
harness.Projections.OnProjectionRemoved(record.WorldEntity!.Id);
|
||||
harness.Projections.OnProjectionRemoved(record);
|
||||
harness.Journal.DrainTo(harness.Scene);
|
||||
|
||||
Assert.True(harness.Runtime.UnregisterLiveEntity(
|
||||
|
|
@ -383,14 +380,11 @@ public sealed class LiveRenderProjectionJournalTests
|
|||
LiveEntityProjectionKind projectionKind =
|
||||
LiveEntityProjectionKind.World)
|
||||
{
|
||||
LiveEntityRecord record =
|
||||
harness.Runtime.RegisterLiveEntity(Spawn(guid, instance)).Record!;
|
||||
WorldEntity? entity = harness.Runtime.MaterializeLiveEntity(
|
||||
guid,
|
||||
CellId,
|
||||
LiveEntityRecord record = harness.Runtime.RegisterAndMaterializeProjection(
|
||||
Spawn(guid, instance),
|
||||
localId => Entity(localId, guid),
|
||||
projectionKind);
|
||||
Assert.NotNull(entity);
|
||||
Assert.NotNull(record.WorldEntity);
|
||||
record.InitialHydrationCompleted = true;
|
||||
return record;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -635,11 +635,10 @@ public sealed class RetailStaticAnimatingObjectSchedulerTests
|
|||
body.SnapToCell(0x01010001u, entity.Position, Vector3.Zero);
|
||||
LiveEntityAnimationState state = LiveState(entity, setup, sequencer);
|
||||
Assert.True(scheduler.BindLiveOwner(entity, state, body));
|
||||
var record = new LiveEntityRecord(Spawn(serverGuid))
|
||||
{
|
||||
WorldEntity = entity,
|
||||
AnimationRuntime = state,
|
||||
};
|
||||
var record = LiveEntityTestFixture.CreateExactProjectionRecord(
|
||||
Spawn(serverGuid));
|
||||
record.WorldEntity = entity;
|
||||
record.AnimationRuntime = state;
|
||||
int motionDone = 0;
|
||||
sequencer.MotionDoneTarget = (_, success) =>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -119,12 +119,12 @@ public sealed class EntityEffectControllerTests
|
|||
EntityEffectProfile? profile = null)
|
||||
{
|
||||
WorldSession.EntitySpawn spawn = Spawn(guid, generation);
|
||||
Runtime.RegisterLiveEntity(spawn);
|
||||
Runtime.SetEffectProfile(guid, profile ?? LiveProfile());
|
||||
WorldEntity entity = Runtime.MaterializeLiveEntity(
|
||||
guid,
|
||||
spawn.Position!.Value.LandblockId,
|
||||
id => Entity(id, guid))!;
|
||||
LiveEntityRecord record = Runtime.RegisterAndMaterializeProjection(
|
||||
spawn,
|
||||
id => Entity(id, guid),
|
||||
initializeProjection: exact =>
|
||||
exact.EffectProfile = profile ?? LiveProfile());
|
||||
WorldEntity entity = Assert.IsType<WorldEntity>(record.WorldEntity);
|
||||
Assert.True(Controller.OnLiveEntityReady(guid));
|
||||
return entity;
|
||||
}
|
||||
|
|
@ -172,12 +172,11 @@ public sealed class EntityEffectControllerTests
|
|||
var fixture = new Fixture();
|
||||
fixture.Controller.HandleDirect(new PlayPhysicsScript(Guid, DirectDid));
|
||||
WorldSession.EntitySpawn spawn = Spawn(Guid, 1);
|
||||
fixture.Runtime.RegisterLiveEntity(spawn);
|
||||
fixture.Runtime.SetEffectProfile(Guid, Fixture.LiveProfile());
|
||||
fixture.Runtime.MaterializeLiveEntity(
|
||||
Guid,
|
||||
spawn.Position!.Value.LandblockId,
|
||||
id => Entity(id, Guid));
|
||||
fixture.Runtime.RegisterAndMaterializeProjection(
|
||||
spawn,
|
||||
id => Entity(id, Guid),
|
||||
initializeProjection: record =>
|
||||
record.EffectProfile = Fixture.LiveProfile());
|
||||
|
||||
Assert.True(fixture.Controller.PrepareLiveEntityOwner(Guid));
|
||||
Assert.Equal(1, fixture.Controller.PendingPacketCount);
|
||||
|
|
@ -279,12 +278,13 @@ public sealed class EntityEffectControllerTests
|
|||
var fixture = new Fixture();
|
||||
fixture.Controller.HandleDirect(new PlayPhysicsScript(Guid, DirectDid));
|
||||
WorldSession.EntitySpawn spawn = Spawn(Guid, 1);
|
||||
fixture.Runtime.RegisterLiveEntity(spawn);
|
||||
fixture.Runtime.SetEffectProfile(Guid, Fixture.LiveProfile());
|
||||
WorldEntity entity = fixture.Runtime.MaterializeLiveEntity(
|
||||
Guid,
|
||||
0x02020001u,
|
||||
id => Entity(id, Guid))!;
|
||||
LiveEntityRecord record = fixture.Runtime.RegisterAndMaterializeProjection(
|
||||
spawn,
|
||||
id => Entity(id, Guid),
|
||||
initializeProjection: exact =>
|
||||
exact.EffectProfile = Fixture.LiveProfile());
|
||||
WorldEntity entity = Assert.IsType<WorldEntity>(record.WorldEntity);
|
||||
fixture.Runtime.RebucketLiveEntity(Guid, 0x02020001u);
|
||||
|
||||
Assert.True(fixture.Controller.OnLiveEntityReady(Guid));
|
||||
Assert.Equal(1, fixture.Controller.PendingPacketCount);
|
||||
|
|
@ -360,6 +360,7 @@ public sealed class EntityEffectControllerTests
|
|||
WorldSession.EntitySpawn first = Spawn(Guid, generation: 1);
|
||||
fixture.Runtime.RegisterLiveEntity(first);
|
||||
|
||||
fixture.Controller.ForgetUnknownOwner(Guid);
|
||||
Assert.True(fixture.Runtime.UnregisterLiveEntity(
|
||||
new DeleteObject.Parsed(Guid, 1),
|
||||
isLocalPlayer: false));
|
||||
|
|
@ -383,11 +384,11 @@ public sealed class EntityEffectControllerTests
|
|||
isLocalPlayer: false));
|
||||
Assert.Equal(1, fixture.Controller.PendingPacketCount);
|
||||
|
||||
fixture.Runtime.SetEffectProfile(Guid, Fixture.LiveProfile());
|
||||
fixture.Runtime.MaterializeLiveEntity(
|
||||
Guid,
|
||||
current.Position!.Value.LandblockId,
|
||||
id => Entity(id, Guid));
|
||||
fixture.Runtime.RegisterAndMaterializeProjection(
|
||||
current,
|
||||
id => Entity(id, Guid),
|
||||
initializeProjection: record =>
|
||||
record.EffectProfile = Fixture.LiveProfile());
|
||||
Assert.True(fixture.Controller.OnLiveEntityReady(Guid));
|
||||
fixture.Runner.Tick(0.0);
|
||||
Assert.Equal([1u], EmitterIds(fixture.Sink));
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ public sealed class EntitySpawnAdapterLifetimeTests
|
|||
var adapter = new EntitySpawnAdapter(textures, _ => MakeSequencer(), meshes);
|
||||
WorldEntity oldEntity = MakeEntity(61u, guid);
|
||||
oldEntity.MeshRefs = [new MeshRef(0x01000100u, Matrix4x4.Identity)];
|
||||
WorldEntity replacement = MakeEntity(62u, guid);
|
||||
WorldEntity replacement = MakeEntity(61u, guid);
|
||||
replacement.MeshRefs = [new MeshRef(0x01000200u, Matrix4x4.Identity)];
|
||||
|
||||
adapter.OnCreate(oldEntity);
|
||||
|
|
@ -280,7 +280,7 @@ public sealed class EntitySpawnAdapterLifetimeTests
|
|||
var adapter = new EntitySpawnAdapter(textures, _ => MakeSequencer(), meshes);
|
||||
WorldEntity oldEntity = MakeEntity(101u, guid);
|
||||
oldEntity.MeshRefs = [new MeshRef((uint)oldMeshId, Matrix4x4.Identity)];
|
||||
WorldEntity replacement = MakeEntity(102u, guid);
|
||||
WorldEntity replacement = MakeEntity(101u, guid);
|
||||
AnimatedEntityState oldState = Assert.IsType<AnimatedEntityState>(adapter.OnCreate(oldEntity));
|
||||
Assert.True(adapter.SetPresentationResident(oldEntity, resident: true));
|
||||
|
||||
|
|
@ -682,7 +682,7 @@ public sealed class EntitySpawnAdapterLifetimeTests
|
|||
adapter.OnCreate(oldEntity);
|
||||
Assert.True(adapter.SetPresentationResident(oldEntity, resident: true));
|
||||
|
||||
WorldEntity replacement = MakeEntity(202u, guid);
|
||||
WorldEntity replacement = MakeEntity(201u, guid);
|
||||
replacement.MeshRefs = [new MeshRef((uint)replacementMesh, Matrix4x4.Identity)];
|
||||
adapter.OnCreate(replacement);
|
||||
Assert.True(adapter.SetPresentationResident(replacement, resident: true));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue