acdream/tests/AcDream.App.Tests/World/DormantLiveEntityStoreTests.cs
Erik 823936ec31 fix(streaming): preserve portal destination ownership
Detach old-world spatial ownership atomically, prioritize destination retirement dependencies, and reveal the viewport at the retail transition edge. Give private paperdoll views independent mesh ownership and retain dormant ACE entities so portal revisits preserve server objects without extending active GPU lifetimes.
2026-07-25 08:35:12 +02:00

115 lines
3.4 KiB
C#

using AcDream.App.World;
using AcDream.Core.Net;
using AcDream.Core.Net.Messages;
namespace AcDream.App.Tests.World;
public sealed class DormantLiveEntityStoreTests
{
private const uint Guid = 0x7000_0042u;
[Theory]
[InlineData(10, 10, (int)DormantCreateDisposition.ExistingGeneration)]
[InlineData(10, 11, (int)DormantCreateDisposition.NewGeneration)]
[InlineData(11, 10, (int)DormantCreateDisposition.StaleGeneration)]
[InlineData(0xFFFF, 0, (int)DormantCreateDisposition.NewGeneration)]
[InlineData(0, 0xFFFF, (int)DormantCreateDisposition.StaleGeneration)]
public void CreateClassification_UsesRetailWrapSafeInstanceOrdering(
ushort retained,
ushort incoming,
int expected)
{
var store = new DormantLiveEntityStore();
store.Retain(Spawn(retained, 0x0101_0001u));
Assert.Equal((DormantCreateDisposition)expected, store.ClassifyCreate(
Spawn(incoming, 0x0101_0001u)));
}
[Fact]
public void LandblockSnapshot_IsCanonicalAndDoesNotConsumeRecords()
{
var store = new DormantLiveEntityStore();
WorldSession.EntitySpawn first = Spawn(1, 0x0101_0001u);
WorldSession.EntitySpawn second = Spawn(2, 0x0202_0123u) with
{
Guid = Guid + 1,
};
store.Retain(first);
store.Retain(second);
Assert.Equal(first, Assert.Single(store.SnapshotLandblock(0x0101_FFFFu)));
Assert.Equal(first, Assert.Single(store.SnapshotLandblock(0x0101_0123u)));
Assert.Equal(2, store.Count);
}
[Fact]
public void ExactDelete_CannotRemoveReusedGuidGeneration()
{
var store = new DormantLiveEntityStore();
store.Retain(Spawn(2, 0x0101_0001u));
Assert.False(store.RemoveExact(
new DeleteObject.Parsed(Guid, InstanceSequence: 1)));
Assert.True(store.Contains(Guid, generation: 2));
Assert.True(store.RemoveExact(
new DeleteObject.Parsed(Guid, InstanceSequence: 2)));
Assert.Equal(0, store.Count);
}
[Fact]
public void Retain_CannotReplaceNewerGenerationWithStaleSnapshot()
{
var store = new DormantLiveEntityStore();
WorldSession.EntitySpawn newer = Spawn(2, 0x0101_0001u) with
{
Name = "newer",
};
store.Retain(newer);
store.Retain(Spawn(1, 0x0202_0001u) with
{
Name = "stale",
});
Assert.True(store.TryGetExact(Guid, generation: 2, out var retained));
Assert.Equal(newer, retained);
}
[Fact]
public void Clear_DrainsSessionLifetime()
{
var store = new DormantLiveEntityStore();
store.Retain(Spawn(1, 0x0101_0001u));
store.Clear();
Assert.Equal(0, store.Count);
}
private static WorldSession.EntitySpawn Spawn(
ushort generation,
uint cell) =>
new(
Guid,
new CreateObject.ServerPosition(
cell,
10f,
20f,
5f,
1f,
0f,
0f,
0f),
SetupTableId: 0x0200_0001u,
AnimPartChanges: [],
TextureChanges: [],
SubPalettes: [],
BasePaletteId: null,
ObjScale: null,
Name: "fixture",
ItemType: 1u,
MotionState: null,
MotionTableId: null,
InstanceSequence: generation);
}