53 lines
2.2 KiB
C#
53 lines
2.2 KiB
C#
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Numerics;
|
|
using AcDream.Core.Physics; // TerrainSurface
|
|
|
|
namespace AcDream.Core.World.Cells;
|
|
|
|
/// <summary>
|
|
/// The unified cell graph: the authoritative id->cell resolver and registry.
|
|
/// Built alongside the legacy render/physics cell systems in Stage 1 and consumed
|
|
/// by nobody (zero behavior change). Retail anchor: CObjCell::GetVisible (pseudo_c:308209).
|
|
/// Worker-thread populated; reads are concurrency-safe.
|
|
/// </summary>
|
|
public sealed class CellGraph
|
|
{
|
|
private readonly ConcurrentDictionary<uint, EnvCell> _envCells = new();
|
|
private readonly ConcurrentDictionary<uint, (TerrainSurface Terrain, Vector3 Origin)> _terrain = new();
|
|
|
|
/// <summary>Player's current cell. Defined for Stage 2; INERT in Stage 1 (no writer).</summary>
|
|
public ObjCell? CurrCell { get; internal set; }
|
|
|
|
public bool Contains(uint envCellId) => _envCells.ContainsKey(envCellId);
|
|
|
|
public void Add(EnvCell cell) => _envCells.TryAdd(cell.Id, cell);
|
|
|
|
/// <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);
|
|
|
|
public void RemoveLandblock(uint landblockPrefix)
|
|
{
|
|
uint lb = landblockPrefix & 0xFFFF0000u;
|
|
_terrain.TryRemove(lb, out _);
|
|
foreach (var id in new List<uint>(_envCells.Keys))
|
|
if ((id & 0xFFFF0000u) == lb) _envCells.TryRemove(id, out _);
|
|
}
|
|
|
|
/// <summary>The universal id->cell resolver (retail CObjCell::GetVisible).</summary>
|
|
public ObjCell? GetVisible(uint id)
|
|
{
|
|
if (id == 0u) return null;
|
|
if ((id & 0xFFFFu) >= 0x100u)
|
|
return _envCells.TryGetValue(id, out var env) ? env : null;
|
|
|
|
uint low = id & 0xFFFFu;
|
|
if (low < 1u || low > 0x40u) return null;
|
|
if (!_terrain.TryGetValue(id & 0xFFFF0000u, out var t)) return null;
|
|
int idx = (int)(low - 1u);
|
|
return LandCell.Synthesize(id, t.Terrain, t.Origin, idx / 8, idx % 8);
|
|
}
|
|
|
|
public ObjCell? Neighbor(ObjCell cell, in CellPortal portal) => GetVisible(portal.OtherCellId);
|
|
}
|