perf(physics): cut production traversal to flat assets

Make prepared flat BSP data authoritative for gameplay while retaining the parsed graph only as an exact sampled referee. Fail production publication when collision package data is genuinely absent, keep idempotent already-cached publication valid, and move cell membership, floor lookup, camera diagnostics, and live/static shape bounds onto the flat representation.

Validated by 8,402 Release tests, a strict dense-Arwic connected gate with 46,309/46,309 exact referee matches, and graceful shutdown.

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-25 17:00:04 +02:00
parent d9446030e6
commit 068a06518d
13 changed files with 743 additions and 43 deletions

View file

@ -92,6 +92,36 @@ public sealed class CollisionShadowVerifierTests
Assert.Equal("False", root.GetProperty("Flat").GetString());
}
[Fact]
public void FlatAuthority_MismatchKeepsFlatResultAndUsesGraphOnlyAsReferee()
{
string directory = NewArtifactDirectory();
PhysicsDataCache cache = CacheWithShadow(directory);
cache.CollisionTraversalMode = CollisionTraversalMode.Flat;
CellPhysics matching = MatchingCell(0xA9B4_0100u);
CellPhysics mismatched = WithFlatPhysics(
matching,
new FlatPhysicsBsp(
-1,
ImmutableArray<FlatPhysicsBspNode>.Empty,
ImmutableArray<int>.Empty,
FlatPolygonTable.Empty));
bool flatResult = CollisionTraversal.HasPhysics(cache, mismatched);
Assert.False(flatResult);
CollisionShadowStats stats = cache.CollisionShadowStats;
Assert.Equal(1, stats.Queries);
Assert.Equal(1, stats.Samples);
Assert.Equal(1, stats.Mismatches);
Assert.Equal(0, stats.Faults);
string artifact = Assert.Single(Directory.EnumerateFiles(directory));
using JsonDocument json = JsonDocument.Parse(File.ReadAllText(artifact));
JsonElement root = json.RootElement;
Assert.Equal("True", root.GetProperty("Graph").GetString());
Assert.Equal("False", root.GetProperty("Flat").GetString());
}
[Fact]
public void MissingFlat_IsRecordedAsFaultAndGraphRemainsAuthoritative()
{

View file

@ -0,0 +1,61 @@
using System.Collections.Immutable;
using AcDream.Core.Physics;
using DatReaderWriter.DBObjs;
namespace AcDream.Core.Tests.Physics;
public sealed class PhysicsDataCacheProductionTests
{
[Fact]
public void CreateProduction_SelectsFlatTraversal()
{
PhysicsDataCache cache = PhysicsDataCache.CreateProduction();
Assert.Equal(
CollisionTraversalMode.Flat,
cache.CollisionTraversalMode);
}
[Fact]
public void ProductionSetupPublication_RejectsMissingPreparedAsset()
{
PhysicsDataCache cache = PhysicsDataCache.CreateProduction();
InvalidOperationException fault = Assert.Throws<InvalidOperationException>(
() => cache.CacheSetup(0x0200_0001u, new Setup()));
Assert.Contains(
"no prepared collision asset",
fault.Message,
StringComparison.Ordinal);
}
[Fact]
public void GraphOracleFixture_StillAcceptsSourceSetup()
{
var cache = new PhysicsDataCache();
cache.CacheSetup(0x0200_0001u, new Setup());
Assert.NotNull(cache.GetSetup(0x0200_0001u));
}
[Fact]
public void ProductionSetupPublication_AllowsIdempotentCachedFlatAsset()
{
PhysicsDataCache cache = PhysicsDataCache.CreateProduction();
var setup = new Setup();
var prepared = new FlatSetupCollision(
ImmutableArray<FlatCollisionCylinder>.Empty,
ImmutableArray<FlatCollisionSphere>.Empty,
0f,
0f,
0f,
0f);
cache.CacheSetup(0x0200_0001u, setup, prepared);
cache.CacheSetup(0x0200_0001u, setup);
Assert.Same(prepared, cache.GetFlatSetup(0x0200_0001u));
}
}

View file

@ -1,6 +1,10 @@
using System.Numerics;
using AcDream.Core.Physics;
using AcDream.Core.World.Cells;
using DatReaderWriter.Enums;
using DatReaderWriter.Types;
using Xunit;
using UcgCellPortal = AcDream.Core.World.Cells.CellPortal;
namespace AcDream.Core.Tests.World.Cells;
@ -11,7 +15,7 @@ public class EnvCellTests
var t = transform ?? Matrix4x4.Identity;
Matrix4x4.Invert(t, out var inv);
return new EnvCell(0xA9B40174u, t, inv, min, max,
System.Array.Empty<CellPortal>(), System.Array.Empty<uint>(),
System.Array.Empty<UcgCellPortal>(), System.Array.Empty<uint>(),
seenOutside: false, containmentBsp: null);
}
@ -30,4 +34,36 @@ public class EnvCellTests
Assert.True(c.PointInCell(new Vector3(105,5,5)));
Assert.False(c.PointInCell(new Vector3(5,5,5)));
}
[Fact]
public void PointInCell_PreparedContainmentIsAuthoritative()
{
var graphRoot = new CellBSPNode
{
Type = BSPNodeType.BPIn,
SplittingPlane = new Plane(Vector3.UnitX, -1f),
PosNode = new CellBSPNode { Type = BSPNodeType.Leaf },
};
var flatRoot = new CellBSPNode
{
Type = BSPNodeType.Leaf,
LeafIndex = 1,
};
FlatCellContainmentBsp flat =
FlatCollisionAssetBuilder.FlattenCellContainmentBsp(flatRoot);
var cell = new EnvCell(
0xA9B4_0174u,
Matrix4x4.Identity,
Matrix4x4.Identity,
-Vector3.One,
Vector3.One,
Array.Empty<UcgCellPortal>(),
Array.Empty<uint>(),
seenOutside: false,
containmentBsp: new CellBSPTree { Root = graphRoot },
flatContainmentBsp: flat);
Assert.True(cell.PointInCell(Vector3.Zero));
Assert.False(BSPQuery.PointInsideCellBsp(graphRoot, Vector3.Zero));
}
}