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:
parent
d9446030e6
commit
068a06518d
13 changed files with 743 additions and 43 deletions
|
|
@ -3,9 +3,9 @@ using System.Numerics;
|
|||
namespace AcDream.Core.Physics;
|
||||
|
||||
/// <summary>
|
||||
/// Temporary Slice I referee mode. Graph remains production-authoritative;
|
||||
/// Flat is enabled only by differential tests until dual publication and the
|
||||
/// connected shadow gate complete.
|
||||
/// Temporary Slice I6 authority/referee selector. Gameplay uses
|
||||
/// <see cref="Flat"/>; <see cref="Graph"/> remains only for the old-oracle
|
||||
/// differential fixtures until the accepted cutover deletes it.
|
||||
/// </summary>
|
||||
internal enum CollisionTraversalMode
|
||||
{
|
||||
|
|
@ -14,8 +14,8 @@ internal enum CollisionTraversalMode
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Narrow representation switch used while the graph and flat collision
|
||||
/// worlds coexist. I6 removes the graph branch after acceptance.
|
||||
/// Narrow representation switch used while flat production and the graph
|
||||
/// referee coexist. I6 removes the graph branch after acceptance.
|
||||
/// </summary>
|
||||
internal static class CollisionTraversal
|
||||
{
|
||||
|
|
@ -27,7 +27,49 @@ internal static class CollisionTraversal
|
|||
{
|
||||
FlatCellContainmentBsp flat = cell.FlatContainmentBsp ??
|
||||
throw MissingFlat("cell containment");
|
||||
return flat.RootIndex >= 0;
|
||||
bool flatAuthorityResult = flat.RootIndex >= 0;
|
||||
CollisionShadowVerifier? flatShadow = cache.CollisionShadow;
|
||||
if (flatShadow is null ||
|
||||
!flatShadow.TrySample(out long flatAuthoritySample))
|
||||
return flatAuthorityResult;
|
||||
|
||||
bool graphRefereeResult = false;
|
||||
Exception? graphRefereeFault = null;
|
||||
flatShadow.BeginGraphPass();
|
||||
try
|
||||
{
|
||||
graphRefereeResult = cell.CellBSP?.Root is not null;
|
||||
}
|
||||
catch (Exception fault)
|
||||
{
|
||||
graphRefereeFault = fault;
|
||||
}
|
||||
finally
|
||||
{
|
||||
flatShadow.EndGraphPass();
|
||||
}
|
||||
|
||||
if (graphRefereeFault is null)
|
||||
{
|
||||
flatShadow.RecordBoolean(
|
||||
flatAuthoritySample,
|
||||
"HasCellContainment",
|
||||
cell.SourceId,
|
||||
graphRefereeResult,
|
||||
flatAuthorityResult,
|
||||
string.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
flatShadow.RecordFault(
|
||||
flatAuthoritySample,
|
||||
"HasCellContainment",
|
||||
cell.SourceId,
|
||||
graphRefereeFault,
|
||||
string.Empty,
|
||||
"flat");
|
||||
}
|
||||
return flatAuthorityResult;
|
||||
}
|
||||
|
||||
CollisionShadowVerifier? shadow = cache.CollisionShadow;
|
||||
|
|
@ -82,7 +124,49 @@ internal static class CollisionTraversal
|
|||
{
|
||||
FlatPhysicsBsp flat = cell.FlatPhysicsBsp ??
|
||||
throw MissingFlat("cell physics");
|
||||
return flat.RootIndex >= 0;
|
||||
bool flatAuthorityResult = flat.RootIndex >= 0;
|
||||
CollisionShadowVerifier? flatShadow = cache.CollisionShadow;
|
||||
if (flatShadow is null ||
|
||||
!flatShadow.TrySample(out long flatAuthoritySample))
|
||||
return flatAuthorityResult;
|
||||
|
||||
bool graphRefereeResult = false;
|
||||
Exception? graphRefereeFault = null;
|
||||
flatShadow.BeginGraphPass();
|
||||
try
|
||||
{
|
||||
graphRefereeResult = cell.BSP?.Root is not null;
|
||||
}
|
||||
catch (Exception fault)
|
||||
{
|
||||
graphRefereeFault = fault;
|
||||
}
|
||||
finally
|
||||
{
|
||||
flatShadow.EndGraphPass();
|
||||
}
|
||||
|
||||
if (graphRefereeFault is null)
|
||||
{
|
||||
flatShadow.RecordBoolean(
|
||||
flatAuthoritySample,
|
||||
"HasCellPhysics",
|
||||
cell.SourceId,
|
||||
graphRefereeResult,
|
||||
flatAuthorityResult,
|
||||
string.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
flatShadow.RecordFault(
|
||||
flatAuthoritySample,
|
||||
"HasCellPhysics",
|
||||
cell.SourceId,
|
||||
graphRefereeFault,
|
||||
string.Empty,
|
||||
"flat");
|
||||
}
|
||||
return flatAuthorityResult;
|
||||
}
|
||||
|
||||
CollisionShadowVerifier? shadow = cache.CollisionShadow;
|
||||
|
|
@ -137,7 +221,49 @@ internal static class CollisionTraversal
|
|||
{
|
||||
FlatPhysicsBsp flat = gfxObject.FlatPhysicsBsp ??
|
||||
throw MissingFlat("GfxObj physics");
|
||||
return flat.RootIndex >= 0;
|
||||
bool flatAuthorityResult = flat.RootIndex >= 0;
|
||||
CollisionShadowVerifier? flatShadow = cache.CollisionShadow;
|
||||
if (flatShadow is null ||
|
||||
!flatShadow.TrySample(out long flatAuthoritySample))
|
||||
return flatAuthorityResult;
|
||||
|
||||
bool graphRefereeResult = false;
|
||||
Exception? graphRefereeFault = null;
|
||||
flatShadow.BeginGraphPass();
|
||||
try
|
||||
{
|
||||
graphRefereeResult = gfxObject.BSP.Root is not null;
|
||||
}
|
||||
catch (Exception fault)
|
||||
{
|
||||
graphRefereeFault = fault;
|
||||
}
|
||||
finally
|
||||
{
|
||||
flatShadow.EndGraphPass();
|
||||
}
|
||||
|
||||
if (graphRefereeFault is null)
|
||||
{
|
||||
flatShadow.RecordBoolean(
|
||||
flatAuthoritySample,
|
||||
"HasGfxObjPhysics",
|
||||
gfxObject.SourceId,
|
||||
graphRefereeResult,
|
||||
flatAuthorityResult,
|
||||
string.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
flatShadow.RecordFault(
|
||||
flatAuthoritySample,
|
||||
"HasGfxObjPhysics",
|
||||
gfxObject.SourceId,
|
||||
graphRefereeFault,
|
||||
string.Empty,
|
||||
"flat");
|
||||
}
|
||||
return flatAuthorityResult;
|
||||
}
|
||||
|
||||
CollisionShadowVerifier? shadow = cache.CollisionShadow;
|
||||
|
|
@ -192,7 +318,43 @@ internal static class CollisionTraversal
|
|||
{
|
||||
FlatPhysicsBsp flat = cell.FlatPhysicsBsp ??
|
||||
throw MissingFlat("cell physics");
|
||||
return flat.Nodes[flat.RootIndex].BoundingSphere;
|
||||
FlatCollisionSphere flatAuthorityResult =
|
||||
flat.Nodes[flat.RootIndex].BoundingSphere;
|
||||
CollisionShadowVerifier? flatShadow = cache.CollisionShadow;
|
||||
if (flatShadow is null ||
|
||||
!flatShadow.TrySample(out long flatAuthoritySample))
|
||||
return flatAuthorityResult;
|
||||
|
||||
try
|
||||
{
|
||||
flatShadow.BeginGraphPass();
|
||||
DatReaderWriter.Types.Sphere graphSphere =
|
||||
cell.BSP!.Root!.BoundingSphere;
|
||||
var graphRefereeResult =
|
||||
new FlatCollisionSphere(
|
||||
graphSphere.Origin,
|
||||
graphSphere.Radius);
|
||||
flatShadow.EndGraphPass();
|
||||
flatShadow.RecordSphere(
|
||||
flatAuthoritySample,
|
||||
"RootBoundingSphere",
|
||||
cell.SourceId,
|
||||
graphRefereeResult,
|
||||
flatAuthorityResult);
|
||||
}
|
||||
catch (Exception fault)
|
||||
{
|
||||
if (flatShadow.IsGraphPass)
|
||||
flatShadow.EndGraphPass();
|
||||
flatShadow.RecordFault(
|
||||
flatAuthoritySample,
|
||||
"RootBoundingSphere",
|
||||
cell.SourceId,
|
||||
fault,
|
||||
string.Empty,
|
||||
"flat");
|
||||
}
|
||||
return flatAuthorityResult;
|
||||
}
|
||||
|
||||
DatReaderWriter.Types.Sphere sphere = cell.BSP!.Root!.BoundingSphere;
|
||||
|
|
@ -240,7 +402,54 @@ internal static class CollisionTraversal
|
|||
{
|
||||
FlatCellContainmentBsp flat = cell.FlatContainmentBsp ??
|
||||
throw MissingFlat("cell containment");
|
||||
return FlatBspQuery.PointInsideCellBsp(flat, localPoint);
|
||||
bool flatAuthorityResult =
|
||||
FlatBspQuery.PointInsideCellBsp(flat, localPoint);
|
||||
CollisionShadowVerifier? flatShadow = cache.CollisionShadow;
|
||||
if (flatShadow is null ||
|
||||
!flatShadow.TrySample(out long flatAuthoritySample))
|
||||
return flatAuthorityResult;
|
||||
|
||||
bool graphRefereeResult = false;
|
||||
Exception? graphRefereeFault = null;
|
||||
flatShadow.BeginGraphPass();
|
||||
try
|
||||
{
|
||||
graphRefereeResult = BSPQuery.PointInsideCellBsp(
|
||||
cell.CellBSP?.Root,
|
||||
localPoint);
|
||||
}
|
||||
catch (Exception fault)
|
||||
{
|
||||
graphRefereeFault = fault;
|
||||
}
|
||||
finally
|
||||
{
|
||||
flatShadow.EndGraphPass();
|
||||
}
|
||||
string flatAuthorityInput = CollisionShadowVerifier.FormatInput(
|
||||
localPoint,
|
||||
0f);
|
||||
if (graphRefereeFault is null)
|
||||
{
|
||||
flatShadow.RecordBoolean(
|
||||
flatAuthoritySample,
|
||||
"PointInsideCell",
|
||||
cell.SourceId,
|
||||
graphRefereeResult,
|
||||
flatAuthorityResult,
|
||||
flatAuthorityInput);
|
||||
}
|
||||
else
|
||||
{
|
||||
flatShadow.RecordFault(
|
||||
flatAuthoritySample,
|
||||
"PointInsideCell",
|
||||
cell.SourceId,
|
||||
graphRefereeFault,
|
||||
flatAuthorityInput,
|
||||
"flat");
|
||||
}
|
||||
return flatAuthorityResult;
|
||||
}
|
||||
|
||||
CollisionShadowVerifier? shadow = cache.CollisionShadow;
|
||||
|
|
@ -305,10 +514,57 @@ internal static class CollisionTraversal
|
|||
{
|
||||
FlatCellContainmentBsp flat = cell.FlatContainmentBsp ??
|
||||
throw MissingFlat("cell containment");
|
||||
return FlatBspQuery.SphereIntersectsCellBsp(
|
||||
bool flatAuthorityResult = FlatBspQuery.SphereIntersectsCellBsp(
|
||||
flat,
|
||||
localCenter,
|
||||
radius);
|
||||
CollisionShadowVerifier? flatShadow = cache.CollisionShadow;
|
||||
if (flatShadow is null ||
|
||||
!flatShadow.TrySample(out long flatAuthoritySample))
|
||||
return flatAuthorityResult;
|
||||
|
||||
bool graphRefereeResult = false;
|
||||
Exception? graphRefereeFault = null;
|
||||
flatShadow.BeginGraphPass();
|
||||
try
|
||||
{
|
||||
graphRefereeResult = BSPQuery.SphereIntersectsCellBsp(
|
||||
cell.CellBSP?.Root,
|
||||
localCenter,
|
||||
radius);
|
||||
}
|
||||
catch (Exception fault)
|
||||
{
|
||||
graphRefereeFault = fault;
|
||||
}
|
||||
finally
|
||||
{
|
||||
flatShadow.EndGraphPass();
|
||||
}
|
||||
string flatAuthorityInput = CollisionShadowVerifier.FormatInput(
|
||||
localCenter,
|
||||
radius);
|
||||
if (graphRefereeFault is null)
|
||||
{
|
||||
flatShadow.RecordBoolean(
|
||||
flatAuthoritySample,
|
||||
"SphereIntersectsCell",
|
||||
cell.SourceId,
|
||||
graphRefereeResult,
|
||||
flatAuthorityResult,
|
||||
flatAuthorityInput);
|
||||
}
|
||||
else
|
||||
{
|
||||
flatShadow.RecordFault(
|
||||
flatAuthoritySample,
|
||||
"SphereIntersectsCell",
|
||||
cell.SourceId,
|
||||
graphRefereeFault,
|
||||
flatAuthorityInput,
|
||||
"flat");
|
||||
}
|
||||
return flatAuthorityResult;
|
||||
}
|
||||
|
||||
CollisionShadowVerifier? shadow = cache.CollisionShadow;
|
||||
|
|
@ -386,9 +642,17 @@ internal static class CollisionTraversal
|
|||
{
|
||||
if (UseFlat(cache))
|
||||
{
|
||||
CollisionShadowVerifier? flatShadow = cache.CollisionShadow;
|
||||
long flatAuthoritySample = 0;
|
||||
bool sampled =
|
||||
flatShadow is not null &&
|
||||
flatShadow.TrySample(out flatAuthoritySample);
|
||||
Transition? graphTransition = sampled
|
||||
? flatShadow!.PrepareShadow(transition)
|
||||
: null;
|
||||
FlatPhysicsBsp flat = cell.FlatPhysicsBsp ??
|
||||
throw MissingFlat("cell physics");
|
||||
return FlatBspQuery.FindCollisions(
|
||||
TransitionState flatAuthorityState = FlatBspQuery.FindCollisions(
|
||||
flat,
|
||||
transition,
|
||||
localSphereCenter,
|
||||
|
|
@ -402,6 +666,73 @@ internal static class CollisionTraversal
|
|||
localToWorld,
|
||||
engine,
|
||||
worldOrigin);
|
||||
if (!sampled)
|
||||
return flatAuthorityState;
|
||||
|
||||
TransitionState graphRefereeState = TransitionState.Invalid;
|
||||
Exception? graphRefereeFault = null;
|
||||
flatShadow!.BeginGraphPass();
|
||||
try
|
||||
{
|
||||
graphRefereeState = BSPQuery.FindCollisions(
|
||||
cell.BSP?.Root,
|
||||
cell.Resolved,
|
||||
graphTransition!,
|
||||
localSphereCenter,
|
||||
localSphereRadius,
|
||||
hasLocalSphere1,
|
||||
localSphere1Center,
|
||||
localSphere1Radius,
|
||||
localCurrentCenter,
|
||||
localSpaceZ,
|
||||
scale,
|
||||
localToWorld,
|
||||
engine,
|
||||
worldOrigin);
|
||||
}
|
||||
catch (Exception fault)
|
||||
{
|
||||
graphRefereeFault = fault;
|
||||
}
|
||||
finally
|
||||
{
|
||||
flatShadow.EndGraphPass();
|
||||
}
|
||||
|
||||
string flatAuthorityInput = CollisionShadowVerifier.FormatInput(
|
||||
localSphereCenter,
|
||||
localSphereRadius,
|
||||
hasLocalSphere1,
|
||||
localSphere1Center,
|
||||
localSphere1Radius,
|
||||
localCurrentCenter,
|
||||
localSpaceZ,
|
||||
scale,
|
||||
localToWorld,
|
||||
worldOrigin);
|
||||
if (graphRefereeFault is null)
|
||||
{
|
||||
flatShadow.RecordTransition(
|
||||
flatAuthoritySample,
|
||||
"FindCellCollisions",
|
||||
cell.SourceId,
|
||||
graphRefereeState,
|
||||
flatAuthorityState,
|
||||
graphTransition!,
|
||||
transition,
|
||||
flatAuthorityInput);
|
||||
}
|
||||
else
|
||||
{
|
||||
flatShadow.RecordFault(
|
||||
flatAuthoritySample,
|
||||
"FindCellCollisions",
|
||||
cell.SourceId,
|
||||
graphRefereeFault,
|
||||
flatAuthorityInput,
|
||||
"flat");
|
||||
}
|
||||
return flatAuthorityState;
|
||||
}
|
||||
|
||||
CollisionShadowVerifier? shadow = cache.CollisionShadow;
|
||||
|
|
@ -523,9 +854,17 @@ internal static class CollisionTraversal
|
|||
{
|
||||
if (UseFlat(cache))
|
||||
{
|
||||
CollisionShadowVerifier? flatShadow = cache.CollisionShadow;
|
||||
long flatAuthoritySample = 0;
|
||||
bool sampled =
|
||||
flatShadow is not null &&
|
||||
flatShadow.TrySample(out flatAuthoritySample);
|
||||
Transition? graphTransition = sampled
|
||||
? flatShadow!.PrepareShadow(transition)
|
||||
: null;
|
||||
FlatPhysicsBsp flat = gfxObject.FlatPhysicsBsp ??
|
||||
throw MissingFlat("GfxObj physics");
|
||||
return FlatBspQuery.FindCollisions(
|
||||
TransitionState flatAuthorityState = FlatBspQuery.FindCollisions(
|
||||
flat,
|
||||
transition,
|
||||
localSphereCenter,
|
||||
|
|
@ -539,6 +878,73 @@ internal static class CollisionTraversal
|
|||
localToWorld,
|
||||
engine,
|
||||
worldOrigin);
|
||||
if (!sampled)
|
||||
return flatAuthorityState;
|
||||
|
||||
TransitionState graphRefereeState = TransitionState.Invalid;
|
||||
Exception? graphRefereeFault = null;
|
||||
flatShadow!.BeginGraphPass();
|
||||
try
|
||||
{
|
||||
graphRefereeState = BSPQuery.FindCollisions(
|
||||
gfxObject.BSP.Root,
|
||||
gfxObject.Resolved,
|
||||
graphTransition!,
|
||||
localSphereCenter,
|
||||
localSphereRadius,
|
||||
hasLocalSphere1,
|
||||
localSphere1Center,
|
||||
localSphere1Radius,
|
||||
localCurrentCenter,
|
||||
localSpaceZ,
|
||||
scale,
|
||||
localToWorld,
|
||||
engine,
|
||||
worldOrigin);
|
||||
}
|
||||
catch (Exception fault)
|
||||
{
|
||||
graphRefereeFault = fault;
|
||||
}
|
||||
finally
|
||||
{
|
||||
flatShadow.EndGraphPass();
|
||||
}
|
||||
|
||||
string flatAuthorityInput = CollisionShadowVerifier.FormatInput(
|
||||
localSphereCenter,
|
||||
localSphereRadius,
|
||||
hasLocalSphere1,
|
||||
localSphere1Center,
|
||||
localSphere1Radius,
|
||||
localCurrentCenter,
|
||||
localSpaceZ,
|
||||
scale,
|
||||
localToWorld,
|
||||
worldOrigin);
|
||||
if (graphRefereeFault is null)
|
||||
{
|
||||
flatShadow.RecordTransition(
|
||||
flatAuthoritySample,
|
||||
"FindGfxObjCollisions",
|
||||
gfxObject.SourceId,
|
||||
graphRefereeState,
|
||||
flatAuthorityState,
|
||||
graphTransition!,
|
||||
transition,
|
||||
flatAuthorityInput);
|
||||
}
|
||||
else
|
||||
{
|
||||
flatShadow.RecordFault(
|
||||
flatAuthoritySample,
|
||||
"FindGfxObjCollisions",
|
||||
gfxObject.SourceId,
|
||||
graphRefereeFault,
|
||||
flatAuthorityInput,
|
||||
"flat");
|
||||
}
|
||||
return flatAuthorityState;
|
||||
}
|
||||
|
||||
CollisionShadowVerifier? shadow = cache.CollisionShadow;
|
||||
|
|
@ -642,9 +1048,15 @@ internal static class CollisionTraversal
|
|||
return graphState;
|
||||
}
|
||||
|
||||
private static bool UseFlat(PhysicsDataCache cache) =>
|
||||
cache.CollisionTraversalMode == CollisionTraversalMode.Flat ||
|
||||
cache.CollisionShadow?.IsFlatPass == true;
|
||||
private static bool UseFlat(PhysicsDataCache cache)
|
||||
{
|
||||
CollisionShadowVerifier? shadow = cache.CollisionShadow;
|
||||
if (shadow?.IsGraphPass == true)
|
||||
return false;
|
||||
if (shadow?.IsFlatPass == true)
|
||||
return true;
|
||||
return cache.CollisionTraversalMode == CollisionTraversalMode.Flat;
|
||||
}
|
||||
|
||||
private static InvalidOperationException MissingFlat(string kind) =>
|
||||
new(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue