fix(physics): make collision activation starvation-free
This commit is contained in:
parent
d94145e6b8
commit
6b28ff999c
14 changed files with 4637 additions and 474 deletions
86
src/AcDream.Core/Physics/CollisionWorldState.cs
Normal file
86
src/AcDream.Core/Physics/CollisionWorldState.cs
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
using System.Collections.Concurrent;
|
||||
using AcDream.Core.World.Cells;
|
||||
|
||||
namespace AcDream.Core.Physics;
|
||||
|
||||
/// <summary>
|
||||
/// One exclusive-by-ownership collision-world root. A preparation mutates only
|
||||
/// its private root; activation transfers the complete root through one volatile
|
||||
/// reference publication shared by every collision facade.
|
||||
/// </summary>
|
||||
internal sealed class CollisionWorldState
|
||||
{
|
||||
internal Dictionary<uint, PhysicsEngine.LandblockPhysics> Landblocks { get; } = new();
|
||||
internal List<uint> LandblockSlots { get; } = new();
|
||||
internal Dictionary<uint, int> LandblockIndices { get; } = new();
|
||||
internal Stack<int> LandblockFreeSlots { get; } = new();
|
||||
internal ConcurrentDictionary<uint, CellPhysics> CellStruct { get; } = new();
|
||||
internal ConcurrentDictionary<uint, FlatCellStructureCollisionAsset>
|
||||
FlatCellStruct { get; } = new();
|
||||
internal ConcurrentDictionary<uint, FlatEnvCellTopology> FlatEnvCell { get; } = new();
|
||||
internal ConcurrentDictionary<uint, BuildingPhysics> Buildings { get; } = new();
|
||||
internal ConcurrentDictionary<uint, EnvCell> EnvCells { get; } = new();
|
||||
internal ConcurrentDictionary<uint, CellGraphTerrain> Terrain { get; } = new();
|
||||
internal ConcurrentDictionary<uint, ObjCell> OutdoorCells { get; } = new();
|
||||
internal Dictionary<uint, List<ShadowEntry>> ShadowCells { get; } = new();
|
||||
internal Dictionary<uint, List<uint>> ShadowEntityCells { get; } = new();
|
||||
internal HashSet<uint> SuspendedShadowEntities { get; } = new();
|
||||
internal Dictionary<uint, HashSet<uint>> WithdrawnPrefixesByOwner { get; } = new();
|
||||
internal Dictionary<uint, IReadOnlyList<ShadowShape>> ShadowEntityShapes { get; } = new();
|
||||
internal Dictionary<uint, ShadowObjectRegistry.RegistrationRecord>
|
||||
ShadowEntityRegistrations { get; } = new();
|
||||
internal Dictionary<uint, ulong> ShadowOwnerVersions { get; } = new();
|
||||
internal Dictionary<uint, HashSet<uint>> ShadowOwnerPrefixes { get; } = new();
|
||||
internal Dictionary<uint, List<uint>> ShadowPrefixOwnerSlots { get; } = new();
|
||||
internal Dictionary<uint, Dictionary<uint, int>> ShadowPrefixOwnerIndices { get; } = new();
|
||||
internal Dictionary<uint, Stack<int>> ShadowPrefixFreeSlots { get; } = new();
|
||||
internal List<uint> ShadowOwnerSlots { get; } = new();
|
||||
internal Dictionary<uint, int> ShadowOwnerIndices { get; } = new();
|
||||
internal Stack<int> ShadowOwnerFreeSlots { get; } = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stable indirection shared by PhysicsEngine, PhysicsDataCache, CellGraph,
|
||||
/// and ShadowObjectRegistry. Readers observe either complete root, never a
|
||||
/// mixture assembled by several facade assignments.
|
||||
/// </summary>
|
||||
internal sealed class CollisionWorldStateSlot
|
||||
{
|
||||
private CollisionWorldState? _current = new();
|
||||
private bool _revoked;
|
||||
|
||||
internal CollisionWorldStateSlot()
|
||||
{
|
||||
}
|
||||
|
||||
internal CollisionWorldStateSlot(CollisionWorldState current)
|
||||
{
|
||||
_current = current ?? throw new ArgumentNullException(nameof(current));
|
||||
}
|
||||
|
||||
internal CollisionWorldState Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_revoked)
|
||||
throw new ObjectDisposedException("Transferred collision generation");
|
||||
return Volatile.Read(ref _current)
|
||||
?? throw new ObjectDisposedException("Transferred collision generation");
|
||||
}
|
||||
}
|
||||
|
||||
internal CollisionWorldState TransferTo(CollisionWorldStateSlot destination)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(destination);
|
||||
if (_revoked)
|
||||
throw new ObjectDisposedException("Transferred collision generation");
|
||||
CollisionWorldState transferred = _current
|
||||
?? throw new ObjectDisposedException("Transferred collision generation");
|
||||
_revoked = true;
|
||||
Volatile.Write(ref destination._current, transferred);
|
||||
_current = null;
|
||||
return transferred;
|
||||
}
|
||||
|
||||
internal CollisionWorldState Capture() => Current;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue