53 lines
2.3 KiB
C#
53 lines
2.3 KiB
C#
using VoxelEngine.World.Chunk;
|
|
|
|
namespace VoxelEngine.World.Streaming;
|
|
|
|
// Snapshots of the six cardinal neighbor chunks' block arrays, taken on the
|
|
// main thread at job-dispatch time. Each slot is null if that neighbor is not
|
|
// currently loaded. The ChunkMesher reads only these arrays from a worker
|
|
// thread — never the live World.
|
|
public sealed class NeighborSnapshots
|
|
{
|
|
public ushort[]? NegX { get; }
|
|
public ushort[]? PosX { get; }
|
|
public ushort[]? NegY { get; }
|
|
public ushort[]? PosY { get; }
|
|
public ushort[]? NegZ { get; }
|
|
public ushort[]? PosZ { get; }
|
|
|
|
// Snapshots take ownership of the arrays passed in. Callers must hand
|
|
// in fresh copies (not live references into a chunk's _ids buffer) —
|
|
// the snapshot does NOT copy defensively. This is enforced at the
|
|
// single call-site in ChunkStreamer.SnapshotNeighbors which allocates
|
|
// fresh arrays. The arrays must not be mutated after construction.
|
|
public NeighborSnapshots(
|
|
ushort[]? negX, ushort[]? posX,
|
|
ushort[]? negY, ushort[]? posY,
|
|
ushort[]? negZ, ushort[]? posZ)
|
|
{
|
|
this.NegX = negX; this.PosX = posX;
|
|
this.NegY = negY; this.PosY = posY;
|
|
this.NegZ = negZ; this.PosZ = posZ;
|
|
}
|
|
|
|
// Returns true if the out-of-chunk position (nx, ny, nz) — exactly one of
|
|
// which is out of [0, Chunk.Chunk.Size) — is occupied by an opaque block
|
|
// in the snapshot. Returns false if the relevant neighbor is null.
|
|
public bool IsOpaqueOutside(int nx, int ny, int nz, Func<ushort, bool> isOpaque)
|
|
{
|
|
ushort[]? n;
|
|
int lx = nx, ly = ny, lz = nz;
|
|
if (nx < 0) { n = this.NegX; lx = Chunk.Chunk.Size - 1; }
|
|
else if (nx >= Chunk.Chunk.Size) { n = this.PosX; lx = 0; }
|
|
else if (ny < 0) { n = this.NegY; ly = Chunk.Chunk.Size - 1; }
|
|
else if (ny >= Chunk.Chunk.Size) { n = this.PosY; ly = 0; }
|
|
else if (nz < 0) { n = this.NegZ; lz = Chunk.Chunk.Size - 1; }
|
|
else if (nz >= Chunk.Chunk.Size) { n = this.PosZ; lz = 0; }
|
|
else return false; // not actually outside — shouldn't happen, mesher guards
|
|
|
|
if (n == null) return false;
|
|
int index = (lx * Chunk.Chunk.Size + ly) * Chunk.Chunk.Size + lz;
|
|
return isOpaque(n[index]);
|
|
}
|
|
}
|