acdream/src/AcDream.Core/Physics/CollisionWorldState.cs

86 lines
3.8 KiB
C#

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;
}