184 lines
6.0 KiB
C#
184 lines
6.0 KiB
C#
using Sand.Core;
|
|
using System.Diagnostics;
|
|
|
|
namespace Sand.ChunkPrototype;
|
|
|
|
public sealed partial class PrototypeSparseSandAdapter
|
|
{
|
|
private const float FieldDecayFactor = 0.84f;
|
|
private const int RenderHaloCells = 1;
|
|
private readonly ChunkResidencyConfig _config;
|
|
private readonly Dictionary<ushort, PrototypeParticle> _particleProfiles = new();
|
|
private readonly Dictionary<ChunkCoord, ChunkCellPage> _cellPages = new();
|
|
private readonly Dictionary<ChunkCoord, ChunkFieldPage> _fieldPages = new();
|
|
private readonly HashSet<ChunkCoord> _dirtyVisualChunks = new();
|
|
private readonly ChunkStepScheduler _scheduler = new();
|
|
private readonly byte[] _rgbaBuffer;
|
|
private readonly byte[] _rgbBuffer;
|
|
private readonly float _ambientTemperature;
|
|
private bool _fullFrameDirty = true;
|
|
private int _stepCounter;
|
|
private int _particleCount;
|
|
private int _moveAttemptCount;
|
|
private int _verticalMoveAttemptCount;
|
|
private int _diagonalMoveAttemptCount;
|
|
private int _lateralMoveAttemptCount;
|
|
private int _swapAttemptCount;
|
|
private int _stalledMovableCount;
|
|
private int _movementOnlyFastPathCount;
|
|
private int _fullRuntimeStepCount;
|
|
private int _fullRuntimeSolidCount;
|
|
private int _fullRuntimeLiquidCount;
|
|
private int _fullRuntimeGasCount;
|
|
private int _movedParticles;
|
|
private int _swappedParticles;
|
|
private ChunkStepStats _lastStepStats;
|
|
|
|
public PrototypeSparseSandAdapter(int width, int height)
|
|
: this(width, height, 22f, null)
|
|
{
|
|
}
|
|
|
|
public PrototypeSparseSandAdapter(int width, int height, ChunkResidencyConfig config)
|
|
: this(width, height, 22f, config)
|
|
{
|
|
}
|
|
|
|
public PrototypeSparseSandAdapter(int width, int height, float ambientTemperature)
|
|
: this(width, height, ambientTemperature, null)
|
|
{
|
|
}
|
|
|
|
public PrototypeSparseSandAdapter(int width, int height, float ambientTemperature, ChunkResidencyConfig? config)
|
|
{
|
|
if (width <= 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(width));
|
|
}
|
|
|
|
if (height <= 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(height));
|
|
}
|
|
|
|
Width = width;
|
|
Height = height;
|
|
_ambientTemperature = ambientTemperature;
|
|
_config = config ?? ChunkResidencyConfig.Default;
|
|
World = new PrototypeChunkResidencyWorld(_config);
|
|
_rgbaBuffer = new byte[width * height * 4];
|
|
_rgbBuffer = new byte[width * height * 3];
|
|
RegisterParticleProfile(CreateLegacyParticle(PrototypeParticleType.Sand));
|
|
RegisterParticleProfile(CreateLegacyParticle(PrototypeParticleType.Water));
|
|
RegisterParticleProfile(CreateLegacyParticle(PrototypeParticleType.Steam));
|
|
RegisterParticleProfile(CreateLegacyParticle(PrototypeParticleType.Wall));
|
|
}
|
|
|
|
public int Width { get; }
|
|
public int Height { get; }
|
|
public PrototypeChunkResidencyWorld World { get; }
|
|
public int ParticleCount => _particleCount;
|
|
public ChunkStepStats LastStepStats => _lastStepStats;
|
|
public int FieldCellCount => _fieldPages.Values.Sum(static page => page.ActiveCellCount);
|
|
public long EstimatedStorageBytes =>
|
|
World.EstimatedLoadedBytes +
|
|
((long)_cellPages.Count * _config.ChunkWidth * _config.ChunkHeight * 16L) +
|
|
((long)_fieldPages.Count * _config.ChunkWidth * _config.ChunkHeight * 20L);
|
|
|
|
public IReadOnlyCollection<(int X, int Y)> Particles
|
|
{
|
|
get
|
|
{
|
|
var particles = new List<(int X, int Y)>(_particleCount);
|
|
foreach (var (coord, page) in _cellPages)
|
|
{
|
|
foreach (var (localX, localY, _) in page.EnumerateOccupied())
|
|
{
|
|
particles.Add((ToWorldX(coord, localX), ToWorldY(coord, localY)));
|
|
}
|
|
}
|
|
|
|
return particles;
|
|
}
|
|
}
|
|
|
|
public IReadOnlyCollection<KeyValuePair<(int X, int Y), PrototypeParticle>> ParticleEntries
|
|
{
|
|
get
|
|
{
|
|
var particles = new List<KeyValuePair<(int X, int Y), PrototypeParticle>>(_particleCount);
|
|
foreach (var (coord, page) in _cellPages)
|
|
{
|
|
foreach (var (localX, localY, particle) in page.EnumerateOccupied())
|
|
{
|
|
particles.Add(new KeyValuePair<(int X, int Y), PrototypeParticle>((ToWorldX(coord, localX), ToWorldY(coord, localY)), particle));
|
|
}
|
|
}
|
|
|
|
return particles;
|
|
}
|
|
}
|
|
|
|
public bool AddParticle(int x, int y, PrototypeParticleType type = PrototypeParticleType.Sand) => AddParticle(x, y, CreateLegacyParticle(type));
|
|
|
|
public void RegisterParticleProfile(PrototypeParticle particle)
|
|
{
|
|
if (!particle.IsEmpty)
|
|
{
|
|
_particleProfiles[particle.TypeId] = particle;
|
|
}
|
|
}
|
|
|
|
private static long ToMicroseconds(long startTimestamp, long endTimestamp)
|
|
{
|
|
if (endTimestamp <= startTimestamp)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return (endTimestamp - startTimestamp) * 1_000_000L / Stopwatch.Frequency;
|
|
}
|
|
|
|
private void ResetStepMetrics()
|
|
{
|
|
_moveAttemptCount = 0;
|
|
_verticalMoveAttemptCount = 0;
|
|
_diagonalMoveAttemptCount = 0;
|
|
_lateralMoveAttemptCount = 0;
|
|
_swapAttemptCount = 0;
|
|
_stalledMovableCount = 0;
|
|
_movementOnlyFastPathCount = 0;
|
|
_fullRuntimeStepCount = 0;
|
|
_fullRuntimeSolidCount = 0;
|
|
_fullRuntimeLiquidCount = 0;
|
|
_fullRuntimeGasCount = 0;
|
|
_movedParticles = 0;
|
|
_swappedParticles = 0;
|
|
}
|
|
|
|
private void RecordMoveAttempt(int deltaX, int deltaY)
|
|
{
|
|
_moveAttemptCount++;
|
|
if (deltaY == 0)
|
|
{
|
|
_lateralMoveAttemptCount++;
|
|
return;
|
|
}
|
|
|
|
if (deltaX == 0)
|
|
{
|
|
_verticalMoveAttemptCount++;
|
|
return;
|
|
}
|
|
|
|
_diagonalMoveAttemptCount++;
|
|
}
|
|
|
|
private void RecordSwapAttempt() => _swapAttemptCount++;
|
|
|
|
private void RecordStalledMovable()
|
|
{
|
|
_stalledMovableCount++;
|
|
}
|
|
}
|