55 lines
1.9 KiB
C#
55 lines
1.9 KiB
C#
// src/AcDream.Core/World/WorldView.cs
|
|
using DatReaderWriter;
|
|
|
|
namespace AcDream.Core.World;
|
|
|
|
public sealed class WorldView
|
|
{
|
|
public uint CenterLandblockId { get; }
|
|
public IReadOnlyList<LoadedLandblock> Landblocks { get; }
|
|
public IEnumerable<WorldEntity> AllEntities => Landblocks.SelectMany(lb => lb.Entities);
|
|
|
|
private WorldView(uint centerLandblockId, IReadOnlyList<LoadedLandblock> landblocks)
|
|
{
|
|
CenterLandblockId = centerLandblockId;
|
|
Landblocks = landblocks;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Load the 3x3 grid of landblocks around <paramref name="centerLandblockId"/>.
|
|
/// Missing neighbors (edges of the world or absent from the cell dat) are silently skipped.
|
|
/// </summary>
|
|
public static WorldView Load(DatCollection dats, uint centerLandblockId)
|
|
{
|
|
var loaded = new List<LoadedLandblock>();
|
|
foreach (var id in NeighborLandblockIds(centerLandblockId))
|
|
{
|
|
var lb = LandblockLoader.Load(dats, id);
|
|
if (lb is not null)
|
|
loaded.Add(lb);
|
|
}
|
|
return new WorldView(centerLandblockId, loaded);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enumerate the 3x3 neighbor landblock ids around a center. Clamps at the world edges
|
|
/// (skipping neighbors that would underflow or overflow the 8-bit coordinate range).
|
|
/// </summary>
|
|
public static IEnumerable<uint> NeighborLandblockIds(uint centerLandblockId)
|
|
{
|
|
int cx = (int)((centerLandblockId >> 24) & 0xFFu);
|
|
int cy = (int)((centerLandblockId >> 16) & 0xFFu);
|
|
|
|
for (int dy = -1; dy <= 1; dy++)
|
|
{
|
|
for (int dx = -1; dx <= 1; dx++)
|
|
{
|
|
int nx = cx + dx;
|
|
int ny = cy + dy;
|
|
if (nx < 0 || nx > 0xFF || ny < 0 || ny > 0xFF)
|
|
continue;
|
|
yield return (uint)((nx << 24) | (ny << 16) | 0xFFFFu);
|
|
}
|
|
}
|
|
}
|
|
}
|