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
|
|
@ -19,7 +19,7 @@ namespace AcDream.Core.World.Cells;
|
|||
public sealed class CellGraph
|
||||
{
|
||||
private readonly ConcurrentDictionary<uint, EnvCell> _envCells = new();
|
||||
private readonly ConcurrentDictionary<uint, (TerrainSurface Terrain, Vector3 Origin)> _terrain = new();
|
||||
private readonly ConcurrentDictionary<uint, CellGraphTerrain> _terrain = new();
|
||||
|
||||
/// <summary>The player's current cell — the render/lighting root. Written ONLY at the
|
||||
/// player chokepoint <see cref="AcDream.Core.Physics.PhysicsEngine.UpdatePlayerCurrCell"/>
|
||||
|
|
@ -34,7 +34,8 @@ public sealed class CellGraph
|
|||
|
||||
/// <param name="landblockPrefix">Any id in the cell's landblock; masked to (id & 0xFFFF0000).</param>
|
||||
public void RegisterTerrain(uint landblockPrefix, TerrainSurface terrain, Vector3 worldOrigin)
|
||||
=> _terrain[landblockPrefix & 0xFFFF0000u] = (terrain, worldOrigin);
|
||||
=> _terrain[landblockPrefix & 0xFFFF0000u] =
|
||||
new CellGraphTerrain(terrain, worldOrigin);
|
||||
|
||||
/// <summary>
|
||||
/// World origin (SW corner) of the landblock containing <paramref name="id"/>,
|
||||
|
|
@ -137,46 +138,36 @@ public sealed class CellGraph
|
|||
var copy = new CellGraph { CurrCell = CurrCell };
|
||||
foreach ((uint id, EnvCell cell) in _envCells)
|
||||
copy._envCells.TryAdd(id, cell);
|
||||
foreach ((uint id, (TerrainSurface Terrain, Vector3 Origin) terrain) in
|
||||
_terrain)
|
||||
foreach ((uint id, CellGraphTerrain terrain) in _terrain)
|
||||
{
|
||||
copy._terrain.TryAdd(id, terrain);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
internal PreparedCellGraphLandblock PrepareLandblockReplacement(
|
||||
uint landblockId)
|
||||
{
|
||||
uint prefix = landblockId & 0xFFFF0000u;
|
||||
KeyValuePair<uint, EnvCell>[] envCells = _envCells
|
||||
.Where(static pair => (pair.Key & 0xFFFFu) >= 0x0100u)
|
||||
.Where(pair => (pair.Key & 0xFFFF0000u) == prefix)
|
||||
.OrderBy(static pair => pair.Key)
|
||||
.ToArray();
|
||||
bool hasTerrain = _terrain.TryGetValue(prefix, out var terrain);
|
||||
return new PreparedCellGraphLandblock(
|
||||
prefix,
|
||||
envCells,
|
||||
hasTerrain,
|
||||
terrain.Terrain,
|
||||
terrain.Origin,
|
||||
CurrCell?.Id ?? 0u);
|
||||
}
|
||||
internal LandblockReplacementBuilder CreateLandblockReplacementBuilder(
|
||||
CellGraph staging,
|
||||
uint landblockId) => new(this, staging, landblockId);
|
||||
|
||||
internal void CommitLandblockReplacement(
|
||||
PreparedCellGraphLandblock replacement)
|
||||
{
|
||||
uint currentCellId = CurrCell?.Id ?? 0u;
|
||||
RemoveLandblock(replacement.LandblockPrefix);
|
||||
for (int index = 0; index < replacement.EnvCellIdsToRemove.Count; index++)
|
||||
_envCells.TryRemove(replacement.EnvCellIdsToRemove[index], out _);
|
||||
if (replacement.HasTerrain)
|
||||
{
|
||||
_terrain[replacement.LandblockPrefix] = (
|
||||
replacement.Terrain!,
|
||||
replacement.Origin);
|
||||
_terrain[replacement.LandblockPrefix] = replacement.Terrain!;
|
||||
}
|
||||
foreach ((uint id, EnvCell cell) in replacement.EnvCells)
|
||||
else
|
||||
{
|
||||
_terrain.TryRemove(replacement.LandblockPrefix, out _);
|
||||
}
|
||||
for (int index = 0; index < replacement.EnvCells.Count; index++)
|
||||
{
|
||||
(uint id, EnvCell cell) = replacement.EnvCells[index];
|
||||
_envCells[id] = cell;
|
||||
}
|
||||
|
||||
uint desiredCurrentCellId =
|
||||
(currentCellId & 0xFFFF0000u) == replacement.LandblockPrefix
|
||||
|
|
@ -188,13 +179,101 @@ public sealed class CellGraph
|
|||
: 0u;
|
||||
if (desiredCurrentCellId != 0u)
|
||||
CurrCell = GetVisible(desiredCurrentCellId);
|
||||
else if ((currentCellId & 0xFFFF0000u)
|
||||
== replacement.LandblockPrefix)
|
||||
CurrCell = null;
|
||||
}
|
||||
|
||||
internal sealed class LandblockReplacementBuilder : IDisposable
|
||||
{
|
||||
private readonly CellGraph _active;
|
||||
private readonly CellGraph _staging;
|
||||
private readonly uint _prefix;
|
||||
private readonly List<KeyValuePair<uint, EnvCell>> _envCells = new();
|
||||
private readonly HashSet<uint> _stagingIds = new();
|
||||
private readonly List<uint> _removeIds = new();
|
||||
private IEnumerator<KeyValuePair<uint, EnvCell>>? _enumerator;
|
||||
private int _phase;
|
||||
|
||||
internal LandblockReplacementBuilder(
|
||||
CellGraph active,
|
||||
CellGraph staging,
|
||||
uint landblockId)
|
||||
{
|
||||
_active = active;
|
||||
_staging = staging;
|
||||
_prefix = landblockId & 0xFFFF0000u;
|
||||
_enumerator = staging._envCells.GetEnumerator();
|
||||
}
|
||||
|
||||
internal bool Advance()
|
||||
{
|
||||
if (_phase == 0)
|
||||
{
|
||||
if (_enumerator!.MoveNext())
|
||||
{
|
||||
KeyValuePair<uint, EnvCell> pair = _enumerator.Current;
|
||||
if ((pair.Key & 0xFFFF0000u) == _prefix
|
||||
&& (pair.Key & 0xFFFFu) >= 0x0100u)
|
||||
{
|
||||
_envCells.Add(pair);
|
||||
_stagingIds.Add(pair.Key);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
_enumerator.Dispose();
|
||||
_enumerator = _active._envCells.GetEnumerator();
|
||||
_phase = 1;
|
||||
return false;
|
||||
}
|
||||
if (_phase == 1)
|
||||
{
|
||||
if (_enumerator!.MoveNext())
|
||||
{
|
||||
uint id = _enumerator.Current.Key;
|
||||
if ((id & 0xFFFF0000u) == _prefix
|
||||
&& (id & 0xFFFFu) >= 0x0100u
|
||||
&& !_stagingIds.Contains(id))
|
||||
{
|
||||
_removeIds.Add(id);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
_enumerator.Dispose();
|
||||
_enumerator = null;
|
||||
bool hasTerrain = _staging._terrain.TryGetValue(
|
||||
_prefix,
|
||||
out var terrain);
|
||||
Prepared = new PreparedCellGraphLandblock(
|
||||
_prefix,
|
||||
_removeIds,
|
||||
_envCells,
|
||||
hasTerrain,
|
||||
terrain,
|
||||
_staging.CurrCell?.Id ?? 0u);
|
||||
_phase = 2;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
internal PreparedCellGraphLandblock? Prepared { get; private set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_enumerator?.Dispose();
|
||||
_enumerator = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed record PreparedCellGraphLandblock(
|
||||
uint LandblockPrefix,
|
||||
KeyValuePair<uint, EnvCell>[] EnvCells,
|
||||
IReadOnlyList<uint> EnvCellIdsToRemove,
|
||||
IReadOnlyList<KeyValuePair<uint, EnvCell>> EnvCells,
|
||||
bool HasTerrain,
|
||||
TerrainSurface? Terrain,
|
||||
Vector3 Origin,
|
||||
CellGraphTerrain? Terrain,
|
||||
uint CurrentCellId);
|
||||
|
||||
internal sealed record CellGraphTerrain(
|
||||
TerrainSurface Terrain,
|
||||
Vector3 Origin);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue