fix(physics): seal collision generations before activation
This commit is contained in:
parent
be94bc9b06
commit
d94145e6b8
15 changed files with 1556 additions and 410 deletions
|
|
@ -121,31 +121,24 @@ public sealed class PhysicsDataCache
|
|||
return copy;
|
||||
}
|
||||
|
||||
internal PreparedPhysicsDataCacheLandblock PrepareLandblockReplacement(
|
||||
internal LandblockReplacementBuilder CreateLandblockReplacementBuilder(
|
||||
PhysicsDataCache staging,
|
||||
uint landblockId,
|
||||
ReadOnlySpan<uint> gfxObjectIds,
|
||||
ReadOnlySpan<uint> setupIds)
|
||||
{
|
||||
uint prefix = landblockId & 0xFFFF0000u;
|
||||
return new PreparedPhysicsDataCacheLandblock(
|
||||
prefix,
|
||||
CaptureRequested(_gfxObj, gfxObjectIds),
|
||||
CaptureRequested(_visualBounds, gfxObjectIds),
|
||||
CaptureRequested(_flatGfxObj, gfxObjectIds),
|
||||
CaptureRequested(_setup, setupIds),
|
||||
CaptureRequested(_flatSetup, setupIds),
|
||||
CapturePrefix(_cellStruct, prefix),
|
||||
CapturePrefix(_flatCellStruct, prefix),
|
||||
CapturePrefix(_flatEnvCell, prefix),
|
||||
CapturePrefix(_buildings, prefix),
|
||||
CellGraph.PrepareLandblockReplacement(prefix));
|
||||
}
|
||||
uint[] gfxObjectIds,
|
||||
uint[] setupIds) => new(
|
||||
this,
|
||||
staging,
|
||||
landblockId,
|
||||
gfxObjectIds,
|
||||
setupIds);
|
||||
|
||||
internal void CommitLandblockReplacement(
|
||||
PreparedPhysicsDataCacheLandblock replacement)
|
||||
{
|
||||
RemoveCellsForLandblock(replacement.LandblockPrefix);
|
||||
RemoveBuildingsForLandblock(replacement.LandblockPrefix);
|
||||
RemoveEntries(_cellStruct, replacement.CellIdsToRemove);
|
||||
RemoveEntries(_flatCellStruct, replacement.FlatCellIdsToRemove);
|
||||
RemoveEntries(_flatEnvCell, replacement.FlatEnvCellIdsToRemove);
|
||||
RemoveEntries(_buildings, replacement.BuildingIdsToRemove);
|
||||
CommitEntries(_gfxObj, replacement.GfxObjects, replace: false);
|
||||
CommitEntries(_visualBounds, replacement.VisualBounds, replace: false);
|
||||
CommitEntries(_flatGfxObj, replacement.FlatGfxObjects, replace: false);
|
||||
|
|
@ -166,34 +159,14 @@ public sealed class PhysicsDataCache
|
|||
destination.TryAdd(id, value);
|
||||
}
|
||||
|
||||
private static KeyValuePair<uint, T>[] CaptureRequested<T>(
|
||||
ConcurrentDictionary<uint, T> source,
|
||||
ReadOnlySpan<uint> ids)
|
||||
{
|
||||
var result = new List<KeyValuePair<uint, T>>(ids.Length);
|
||||
for (int index = 0; index < ids.Length; index++)
|
||||
{
|
||||
uint id = ids[index];
|
||||
if (source.TryGetValue(id, out T? value))
|
||||
result.Add(new KeyValuePair<uint, T>(id, value));
|
||||
}
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
private static KeyValuePair<uint, T>[] CapturePrefix<T>(
|
||||
ConcurrentDictionary<uint, T> source,
|
||||
uint prefix) => source
|
||||
.Where(pair => (pair.Key & 0xFFFF0000u) == prefix)
|
||||
.OrderBy(static pair => pair.Key)
|
||||
.ToArray();
|
||||
|
||||
private static void CommitEntries<T>(
|
||||
ConcurrentDictionary<uint, T> destination,
|
||||
KeyValuePair<uint, T>[] entries,
|
||||
IReadOnlyList<KeyValuePair<uint, T>> entries,
|
||||
bool replace)
|
||||
{
|
||||
foreach ((uint id, T value) in entries)
|
||||
for (int index = 0; index < entries.Count; index++)
|
||||
{
|
||||
(uint id, T value) = entries[index];
|
||||
if (replace)
|
||||
destination[id] = value;
|
||||
else
|
||||
|
|
@ -201,6 +174,14 @@ public sealed class PhysicsDataCache
|
|||
}
|
||||
}
|
||||
|
||||
private static void RemoveEntries<T>(
|
||||
ConcurrentDictionary<uint, T> destination,
|
||||
IReadOnlyList<uint> ids)
|
||||
{
|
||||
for (int index = 0; index < ids.Count; index++)
|
||||
destination.TryRemove(ids[index], out _);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract and cache the physics BSP + polygon data from a GfxObj,
|
||||
/// PLUS always cache a visual AABB from the vertex data regardless of
|
||||
|
|
@ -1043,19 +1024,268 @@ public sealed class PhysicsDataCache
|
|||
|
||||
/// <summary>Test helper, mirrors <see cref="RegisterCellStructForTest"/>.</summary>
|
||||
public void RegisterBuildingForTest(uint landcellId, BuildingPhysics b) => _buildings[landcellId] = b;
|
||||
|
||||
internal sealed class LandblockReplacementBuilder : IDisposable
|
||||
{
|
||||
private readonly PhysicsDataCache _active;
|
||||
private readonly PhysicsDataCache _staging;
|
||||
private readonly uint _prefix;
|
||||
private readonly uint[] _gfxIds;
|
||||
private readonly uint[] _setupIds;
|
||||
private readonly List<KeyValuePair<uint, GfxObjPhysics>> _gfx = new();
|
||||
private readonly List<KeyValuePair<uint, GfxObjVisualBounds>> _bounds = new();
|
||||
private readonly List<KeyValuePair<uint, FlatGfxObjCollisionAsset>> _flatGfx = new();
|
||||
private readonly List<KeyValuePair<uint, SetupPhysics>> _setups = new();
|
||||
private readonly List<KeyValuePair<uint, FlatSetupCollision>> _flatSetups = new();
|
||||
private readonly List<KeyValuePair<uint, CellPhysics>> _cells = new();
|
||||
private readonly List<KeyValuePair<uint, FlatCellStructureCollisionAsset>> _flatCells = new();
|
||||
private readonly List<KeyValuePair<uint, FlatEnvCellTopology>> _flatEnvCells = new();
|
||||
private readonly List<KeyValuePair<uint, BuildingPhysics>> _buildings = new();
|
||||
private readonly HashSet<uint> _cellIds = new();
|
||||
private readonly HashSet<uint> _flatCellIds = new();
|
||||
private readonly HashSet<uint> _flatEnvCellIds = new();
|
||||
private readonly HashSet<uint> _buildingIds = new();
|
||||
private readonly List<uint> _removeCells = new();
|
||||
private readonly List<uint> _removeFlatCells = new();
|
||||
private readonly List<uint> _removeFlatEnvCells = new();
|
||||
private readonly List<uint> _removeBuildings = new();
|
||||
private readonly UcgCellGraph.LandblockReplacementBuilder _cellGraph;
|
||||
private IEnumerator<KeyValuePair<uint, CellPhysics>>? _cellEnumerator;
|
||||
private IEnumerator<KeyValuePair<uint, FlatCellStructureCollisionAsset>>? _flatCellEnumerator;
|
||||
private IEnumerator<KeyValuePair<uint, FlatEnvCellTopology>>? _flatEnvEnumerator;
|
||||
private IEnumerator<KeyValuePair<uint, BuildingPhysics>>? _buildingEnumerator;
|
||||
private int _phase;
|
||||
private int _cursor;
|
||||
|
||||
internal LandblockReplacementBuilder(
|
||||
PhysicsDataCache active,
|
||||
PhysicsDataCache staging,
|
||||
uint landblockId,
|
||||
uint[] gfxIds,
|
||||
uint[] setupIds)
|
||||
{
|
||||
_active = active;
|
||||
_staging = staging;
|
||||
_prefix = landblockId & 0xFFFF0000u;
|
||||
_gfxIds = gfxIds;
|
||||
_setupIds = setupIds;
|
||||
_cellGraph = active.CellGraph.CreateLandblockReplacementBuilder(
|
||||
staging.CellGraph,
|
||||
_prefix);
|
||||
}
|
||||
|
||||
internal int WorkUnits { get; private set; }
|
||||
internal PreparedPhysicsDataCacheLandblock? Prepared { get; private set; }
|
||||
|
||||
internal bool Advance()
|
||||
{
|
||||
switch (_phase)
|
||||
{
|
||||
case 0:
|
||||
if (_cursor < _gfxIds.Length)
|
||||
{
|
||||
uint id = _gfxIds[_cursor++];
|
||||
Capture(_staging._gfxObj, id, _gfx);
|
||||
Capture(_staging._visualBounds, id, _bounds);
|
||||
Capture(_staging._flatGfxObj, id, _flatGfx);
|
||||
WorkUnits++;
|
||||
return false;
|
||||
}
|
||||
_cursor = 0;
|
||||
_phase++;
|
||||
return false;
|
||||
case 1:
|
||||
if (_cursor < _setupIds.Length)
|
||||
{
|
||||
uint id = _setupIds[_cursor++];
|
||||
Capture(_staging._setup, id, _setups);
|
||||
Capture(_staging._flatSetup, id, _flatSetups);
|
||||
WorkUnits++;
|
||||
return false;
|
||||
}
|
||||
_phase++;
|
||||
return false;
|
||||
case 2:
|
||||
_cellEnumerator ??= _staging._cellStruct.GetEnumerator();
|
||||
if (CapturePrefixOne(_cellEnumerator, _prefix, _cells, _cellIds))
|
||||
{
|
||||
WorkUnits++;
|
||||
return false;
|
||||
}
|
||||
_cellEnumerator.Dispose();
|
||||
_cellEnumerator = null;
|
||||
_phase++;
|
||||
return false;
|
||||
case 3:
|
||||
_cellEnumerator ??= _active._cellStruct.GetEnumerator();
|
||||
if (CaptureRemovalOne(_cellEnumerator, _prefix, _cellIds, _removeCells))
|
||||
{
|
||||
WorkUnits++;
|
||||
return false;
|
||||
}
|
||||
_cellEnumerator.Dispose();
|
||||
_cellEnumerator = null;
|
||||
_phase++;
|
||||
return false;
|
||||
case 4:
|
||||
_flatCellEnumerator ??= _staging._flatCellStruct.GetEnumerator();
|
||||
if (CapturePrefixOne(_flatCellEnumerator, _prefix, _flatCells, _flatCellIds))
|
||||
{
|
||||
WorkUnits++;
|
||||
return false;
|
||||
}
|
||||
_flatCellEnumerator.Dispose();
|
||||
_flatCellEnumerator = null;
|
||||
_phase++;
|
||||
return false;
|
||||
case 5:
|
||||
_flatCellEnumerator ??= _active._flatCellStruct.GetEnumerator();
|
||||
if (CaptureRemovalOne(_flatCellEnumerator, _prefix, _flatCellIds, _removeFlatCells))
|
||||
{
|
||||
WorkUnits++;
|
||||
return false;
|
||||
}
|
||||
_flatCellEnumerator.Dispose();
|
||||
_flatCellEnumerator = null;
|
||||
_phase++;
|
||||
return false;
|
||||
case 6:
|
||||
_flatEnvEnumerator ??= _staging._flatEnvCell.GetEnumerator();
|
||||
if (CapturePrefixOne(_flatEnvEnumerator, _prefix, _flatEnvCells, _flatEnvCellIds))
|
||||
{
|
||||
WorkUnits++;
|
||||
return false;
|
||||
}
|
||||
_flatEnvEnumerator.Dispose();
|
||||
_flatEnvEnumerator = null;
|
||||
_phase++;
|
||||
return false;
|
||||
case 7:
|
||||
_flatEnvEnumerator ??= _active._flatEnvCell.GetEnumerator();
|
||||
if (CaptureRemovalOne(_flatEnvEnumerator, _prefix, _flatEnvCellIds, _removeFlatEnvCells))
|
||||
{
|
||||
WorkUnits++;
|
||||
return false;
|
||||
}
|
||||
_flatEnvEnumerator.Dispose();
|
||||
_flatEnvEnumerator = null;
|
||||
_phase++;
|
||||
return false;
|
||||
case 8:
|
||||
_buildingEnumerator ??= _staging._buildings.GetEnumerator();
|
||||
if (CapturePrefixOne(_buildingEnumerator, _prefix, _buildings, _buildingIds))
|
||||
{
|
||||
WorkUnits++;
|
||||
return false;
|
||||
}
|
||||
_buildingEnumerator.Dispose();
|
||||
_buildingEnumerator = null;
|
||||
_phase++;
|
||||
return false;
|
||||
case 9:
|
||||
_buildingEnumerator ??= _active._buildings.GetEnumerator();
|
||||
if (CaptureRemovalOne(_buildingEnumerator, _prefix, _buildingIds, _removeBuildings))
|
||||
{
|
||||
WorkUnits++;
|
||||
return false;
|
||||
}
|
||||
_buildingEnumerator.Dispose();
|
||||
_buildingEnumerator = null;
|
||||
_phase++;
|
||||
return false;
|
||||
case 10:
|
||||
WorkUnits++;
|
||||
if (!_cellGraph.Advance())
|
||||
return false;
|
||||
Prepared = new PreparedPhysicsDataCacheLandblock(
|
||||
_prefix,
|
||||
_gfx,
|
||||
_bounds,
|
||||
_flatGfx,
|
||||
_setups,
|
||||
_flatSetups,
|
||||
_removeCells,
|
||||
_cells,
|
||||
_removeFlatCells,
|
||||
_flatCells,
|
||||
_removeFlatEnvCells,
|
||||
_flatEnvCells,
|
||||
_removeBuildings,
|
||||
_buildings,
|
||||
_cellGraph.Prepared!);
|
||||
_phase++;
|
||||
return true;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void Capture<T>(
|
||||
ConcurrentDictionary<uint, T> source,
|
||||
uint id,
|
||||
List<KeyValuePair<uint, T>> destination)
|
||||
{
|
||||
if (source.TryGetValue(id, out T? value))
|
||||
destination.Add(new KeyValuePair<uint, T>(id, value));
|
||||
}
|
||||
|
||||
private static bool CapturePrefixOne<T>(
|
||||
IEnumerator<KeyValuePair<uint, T>> enumerator,
|
||||
uint prefix,
|
||||
List<KeyValuePair<uint, T>> destination,
|
||||
HashSet<uint> ids)
|
||||
{
|
||||
if (!enumerator.MoveNext())
|
||||
return false;
|
||||
KeyValuePair<uint, T> pair = enumerator.Current;
|
||||
if ((pair.Key & 0xFFFF0000u) == prefix)
|
||||
{
|
||||
destination.Add(pair);
|
||||
ids.Add(pair.Key);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool CaptureRemovalOne<T>(
|
||||
IEnumerator<KeyValuePair<uint, T>> enumerator,
|
||||
uint prefix,
|
||||
HashSet<uint> retained,
|
||||
List<uint> destination)
|
||||
{
|
||||
if (!enumerator.MoveNext())
|
||||
return false;
|
||||
uint id = enumerator.Current.Key;
|
||||
if ((id & 0xFFFF0000u) == prefix && !retained.Contains(id))
|
||||
destination.Add(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_cellEnumerator?.Dispose();
|
||||
_flatCellEnumerator?.Dispose();
|
||||
_flatEnvEnumerator?.Dispose();
|
||||
_buildingEnumerator?.Dispose();
|
||||
_cellGraph.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed record PreparedPhysicsDataCacheLandblock(
|
||||
uint LandblockPrefix,
|
||||
KeyValuePair<uint, GfxObjPhysics>[] GfxObjects,
|
||||
KeyValuePair<uint, GfxObjVisualBounds>[] VisualBounds,
|
||||
KeyValuePair<uint, FlatGfxObjCollisionAsset>[] FlatGfxObjects,
|
||||
KeyValuePair<uint, SetupPhysics>[] Setups,
|
||||
KeyValuePair<uint, FlatSetupCollision>[] FlatSetups,
|
||||
KeyValuePair<uint, CellPhysics>[] Cells,
|
||||
KeyValuePair<uint, FlatCellStructureCollisionAsset>[] FlatCells,
|
||||
KeyValuePair<uint, FlatEnvCellTopology>[] FlatEnvCells,
|
||||
KeyValuePair<uint, BuildingPhysics>[] Buildings,
|
||||
IReadOnlyList<KeyValuePair<uint, GfxObjPhysics>> GfxObjects,
|
||||
IReadOnlyList<KeyValuePair<uint, GfxObjVisualBounds>> VisualBounds,
|
||||
IReadOnlyList<KeyValuePair<uint, FlatGfxObjCollisionAsset>> FlatGfxObjects,
|
||||
IReadOnlyList<KeyValuePair<uint, SetupPhysics>> Setups,
|
||||
IReadOnlyList<KeyValuePair<uint, FlatSetupCollision>> FlatSetups,
|
||||
IReadOnlyList<uint> CellIdsToRemove,
|
||||
IReadOnlyList<KeyValuePair<uint, CellPhysics>> Cells,
|
||||
IReadOnlyList<uint> FlatCellIdsToRemove,
|
||||
IReadOnlyList<KeyValuePair<uint, FlatCellStructureCollisionAsset>> FlatCells,
|
||||
IReadOnlyList<uint> FlatEnvCellIdsToRemove,
|
||||
IReadOnlyList<KeyValuePair<uint, FlatEnvCellTopology>> FlatEnvCells,
|
||||
IReadOnlyList<uint> BuildingIdsToRemove,
|
||||
IReadOnlyList<KeyValuePair<uint, BuildingPhysics>> Buildings,
|
||||
PreparedCellGraphLandblock CellGraph);
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue