using System.Collections.Concurrent;
using AcDream.Core.World.Cells;
namespace AcDream.Core.Physics;
///
/// 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.
///
internal sealed class CollisionWorldState
{
internal Dictionary Landblocks { get; } = new();
internal List LandblockSlots { get; } = new();
internal Dictionary LandblockIndices { get; } = new();
internal Stack LandblockFreeSlots { get; } = new();
internal ConcurrentDictionary CellStruct { get; } = new();
internal ConcurrentDictionary
FlatCellStruct { get; } = new();
internal ConcurrentDictionary FlatEnvCell { get; } = new();
internal ConcurrentDictionary Buildings { get; } = new();
internal ConcurrentDictionary EnvCells { get; } = new();
internal ConcurrentDictionary Terrain { get; } = new();
internal ConcurrentDictionary OutdoorCells { get; } = new();
internal Dictionary> ShadowCells { get; } = new();
internal Dictionary> ShadowEntityCells { get; } = new();
internal HashSet SuspendedShadowEntities { get; } = new();
internal Dictionary> WithdrawnPrefixesByOwner { get; } = new();
internal Dictionary> ShadowEntityShapes { get; } = new();
internal Dictionary
ShadowEntityRegistrations { get; } = new();
internal Dictionary ShadowOwnerVersions { get; } = new();
internal Dictionary> ShadowOwnerPrefixes { get; } = new();
internal Dictionary> ShadowPrefixOwnerSlots { get; } = new();
internal Dictionary> ShadowPrefixOwnerIndices { get; } = new();
internal Dictionary> ShadowPrefixFreeSlots { get; } = new();
internal List ShadowOwnerSlots { get; } = new();
internal Dictionary ShadowOwnerIndices { get; } = new();
internal Stack ShadowOwnerFreeSlots { get; } = new();
}
///
/// Stable indirection shared by PhysicsEngine, PhysicsDataCache, CellGraph,
/// and ShadowObjectRegistry. Readers observe either complete root, never a
/// mixture assembled by several facade assignments.
///
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;
}