fix(portal): synchronize destination presentation state

This commit is contained in:
Erik 2026-07-16 21:17:13 +02:00
parent 4b1bceefbb
commit e95f55f25b
42 changed files with 2815 additions and 288 deletions

View file

@ -207,6 +207,132 @@ public class ShadowObjectRegistryTests
entry => entry.EntityId == entityId);
}
[Fact]
public void RefloodLandblock_RestoresAdjacentOwnedFootprintWithdrawnByUnload()
{
const uint adjacentOwnerLb = 0xAAB40000u;
const uint ownerCell = adjacentOwnerLb | 1u;
const uint touchedCell = LbId | 57u; // west block cell (7,0)
const uint entityId = 32u;
var reg = new ShadowObjectRegistry();
var cache = new PhysicsDataCache();
cache.CellGraph.RegisterTerrain(
adjacentOwnerLb,
new TerrainSurface(new byte[81], new float[256]),
new Vector3(192f, 0f, 0f));
reg.DataCache = cache;
reg.Register(
entityId,
0x01000006u,
new Vector3(192.5f, 12f, 50f),
Quaternion.Identity,
2f,
192f,
0f,
adjacentOwnerLb,
seedCellId: ownerCell,
isStatic: false);
Assert.Contains(reg.GetObjectsInCell(touchedCell), e => e.EntityId == entityId);
Assert.Contains(reg.GetObjectsInCell(ownerCell), e => e.EntityId == entityId);
reg.RemoveLandblock(LbId);
Assert.DoesNotContain(reg.GetObjectsInCell(touchedCell), e => e.EntityId == entityId);
Assert.Contains(reg.GetObjectsInCell(ownerCell), e => e.EntityId == entityId);
Assert.Equal(1, reg.WithdrawnPrefixMarkerCount);
reg.RefloodLandblock(LbId);
Assert.Contains(reg.GetObjectsInCell(touchedCell), e => e.EntityId == entityId);
Assert.Contains(reg.GetObjectsInCell(ownerCell), e => e.EntityId == entityId);
Assert.Equal(0, reg.WithdrawnPrefixMarkerCount);
}
[Fact]
public void AuthoritativeMove_ClearsObsoleteWithdrawnPrefix()
{
const uint adjacentOwnerLb = 0xAAB40000u;
const uint ownerCell = adjacentOwnerLb | 1u;
const uint touchedCell = LbId | 57u;
const uint entityId = 33u;
var cache = new PhysicsDataCache();
cache.CellGraph.RegisterTerrain(
adjacentOwnerLb,
new TerrainSurface(new byte[81], new float[256]),
new Vector3(192f, 0f, 0f));
var reg = new ShadowObjectRegistry { DataCache = cache };
reg.Register(
entityId, 0x01000007u, new Vector3(192.5f, 12f, 50f),
Quaternion.Identity, 2f, 192f, 0f, adjacentOwnerLb,
seedCellId: ownerCell, isStatic: false);
reg.RemoveLandblock(LbId);
Assert.Equal(1, reg.WithdrawnPrefixMarkerCount);
reg.UpdatePosition(
entityId,
new Vector3(204f, 12f, 50f),
Quaternion.Identity,
192f,
0f,
adjacentOwnerLb,
seedCellId: ownerCell);
Assert.Equal(0, reg.WithdrawnPrefixMarkerCount);
reg.RefloodLandblock(LbId);
Assert.DoesNotContain(reg.GetObjectsInCell(touchedCell), e => e.EntityId == entityId);
}
[Fact]
public void RefloodLandblock_RetiresOnlyCurrentMarker_WhenTwoPrefixesWereWithdrawn()
{
const uint ownerLb = 0xAAB50000u;
const uint ownerCell = ownerLb | 1u;
const uint westLb = 0xA9B50000u;
const uint southLb = 0xAAB40000u;
const uint westCell = westLb | 57u;
const uint southCell = southLb | 8u;
const uint entityId = 35u;
var cache = new PhysicsDataCache();
cache.CellGraph.RegisterTerrain(
ownerLb,
new TerrainSurface(new byte[81], new float[256]),
new Vector3(192f, 192f, 0f));
var reg = new ShadowObjectRegistry { DataCache = cache };
reg.Register(
entityId, 0x01000009u, new Vector3(192.5f, 192.5f, 50f),
Quaternion.Identity, 2f, 192f, 192f, ownerLb,
seedCellId: ownerCell, isStatic: false);
Assert.Contains(reg.GetObjectsInCell(westCell), e => e.EntityId == entityId);
Assert.Contains(reg.GetObjectsInCell(southCell), e => e.EntityId == entityId);
reg.RemoveLandblock(westLb);
reg.RemoveLandblock(southLb);
Assert.Equal(2, reg.WithdrawnPrefixMarkerCount);
reg.RefloodLandblock(westLb);
Assert.Equal(1, reg.WithdrawnPrefixMarkerCount);
reg.RefloodLandblock(southLb);
Assert.Equal(0, reg.WithdrawnPrefixMarkerCount);
Assert.Contains(reg.GetObjectsInCell(westCell), e => e.EntityId == entityId);
Assert.Contains(reg.GetObjectsInCell(southCell), e => e.EntityId == entityId);
}
[Fact]
public void RemoveLandblock_DirectStaticRetirement_ClearsWithdrawnMarker()
{
const uint entityId = 34u;
var reg = new ShadowObjectRegistry();
reg.Register(
entityId, 0x01000008u, new Vector3(12f, 12f, 50f),
Quaternion.Identity, 1f, OffX, OffY, LbId,
isStatic: true);
reg.RemoveLandblock(LbId);
Assert.Equal(0, reg.RetainedRegistrationCount);
Assert.Equal(0, reg.WithdrawnPrefixMarkerCount);
}
// -----------------------------------------------------------------------
// Per-cell query surface (BR-7 / A6.P4 2026-06-11): GetObjectsInCell IS
// the query — retail CObjCell::find_obj_collisions iterates only the