Adds a new public overload accepting an explicit IReadOnlyCollection<uint> cellIds (the camera-buildings' EnvCellIds) instead of a BFS-derived visibility set. Used by RR7's IndoorPass to scope indoor rendering to the camera-buildings' cells, not the full portal BFS (which causes Issues A+C). Pure-data test helper WalkEntitiesForTestByCellIds added alongside the production overload, mirroring the WalkEntitiesForTest pattern. The overload internally delegates to the existing visibleCellIds path — the dispatcher's semantic stays the same; only the caller's intent differs (explicit cell list vs visibility-derived). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
90 lines
3.2 KiB
C#
90 lines
3.2 KiB
C#
// Phase A8 RR5 — verify WbDrawDispatcher.WalkEntitiesForTestByCellIds,
|
|
// the pure-data companion to the new Draw(cellIds:) production overload.
|
|
//
|
|
// Semantics: indoor entities (ParentCellId.HasValue) are gated by explicit
|
|
// membership in cellIds. Building shells (IsBuildingShell) always pass.
|
|
// Outdoor scenery (no ParentCellId, not a shell) is excluded by EntitySet.IndoorPass.
|
|
|
|
using System.Collections.Generic;
|
|
using System.Numerics;
|
|
using AcDream.App.Rendering.Wb;
|
|
using AcDream.Core.World;
|
|
using Xunit;
|
|
|
|
namespace AcDream.Core.Tests.Rendering.Wb;
|
|
|
|
public class WbDrawDispatcherCellIdsOverloadTests
|
|
{
|
|
private static WorldEntity CellEnt(uint id, uint cellId) => new()
|
|
{
|
|
Id = id,
|
|
SourceGfxObjOrSetupId = 0x01000001u,
|
|
ParentCellId = cellId,
|
|
MeshRefs = new List<MeshRef> { new(0x01000001u, Matrix4x4.Identity) },
|
|
Position = Vector3.Zero,
|
|
Rotation = Quaternion.Identity,
|
|
};
|
|
|
|
private static WorldEntity OutdoorScenery(uint id) => new()
|
|
{
|
|
Id = id,
|
|
SourceGfxObjOrSetupId = 0x01000001u,
|
|
ParentCellId = null,
|
|
IsBuildingShell = false,
|
|
MeshRefs = new List<MeshRef> { new(0x01000001u, Matrix4x4.Identity) },
|
|
Position = Vector3.Zero,
|
|
Rotation = Quaternion.Identity,
|
|
};
|
|
|
|
private static WorldEntity BuildingShell(uint id) => new()
|
|
{
|
|
Id = id,
|
|
SourceGfxObjOrSetupId = 0x02000001u,
|
|
ParentCellId = null,
|
|
IsBuildingShell = true,
|
|
MeshRefs = new List<MeshRef> { new(0x01000001u, Matrix4x4.Identity) },
|
|
Position = Vector3.Zero,
|
|
Rotation = Quaternion.Identity,
|
|
};
|
|
|
|
[Fact]
|
|
public void WalkEntitiesByCellIds_IncludesOnlyEntitiesInListedCells()
|
|
{
|
|
var entities = new List<WorldEntity>
|
|
{
|
|
CellEnt(0x40000001u, 0xA9B40150u), // in listed cells
|
|
CellEnt(0x40000002u, 0xA9B40151u), // in listed cells
|
|
CellEnt(0x40000003u, 0xA9B40999u), // OUT — not in list
|
|
BuildingShell(0xC0000001u), // always included (IsBuildingShell)
|
|
OutdoorScenery(0xC0000002u), // OUT — not a shell, not in cell list
|
|
};
|
|
var cellIds = new HashSet<uint> { 0xA9B40150u, 0xA9B40151u };
|
|
|
|
var result = WbDrawDispatcher.WalkEntitiesForTestByCellIds(
|
|
entities, cellIds, set: WbDrawDispatcher.EntitySet.IndoorPass);
|
|
|
|
Assert.Equal(3, result.Count);
|
|
Assert.Contains(0x40000001u, result);
|
|
Assert.Contains(0x40000002u, result);
|
|
Assert.Contains(0xC0000001u, result);
|
|
Assert.DoesNotContain(0x40000003u, result);
|
|
Assert.DoesNotContain(0xC0000002u, result);
|
|
}
|
|
|
|
[Fact]
|
|
public void WalkEntitiesByCellIds_EmptyCellList_StillIncludesBuildingShells()
|
|
{
|
|
var entities = new List<WorldEntity>
|
|
{
|
|
CellEnt(0x40000001u, 0xA9B40150u),
|
|
BuildingShell(0xC0000001u),
|
|
};
|
|
|
|
var result = WbDrawDispatcher.WalkEntitiesForTestByCellIds(
|
|
entities, new HashSet<uint>(), set: WbDrawDispatcher.EntitySet.IndoorPass);
|
|
|
|
// Cell entity dropped (no cells in list); building shell still passes.
|
|
Assert.Single(result);
|
|
Assert.Contains(0xC0000001u, result);
|
|
}
|
|
}
|