using GarmentButton.FlatenArray;
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
namespace GarmentButton.PathFinding
{
[BurstCompile]
public partial struct UpdateSpecificPointSystem : ISystem
{
private const int UPDATE_RADIUS = 5;
[BurstCompile]
public void OnCreate(ref SystemState state)
{
state.RequireForUpdate<GridData>();
state.RequireForUpdate<GridAdditionalData>();
state.RequireForUpdate<RequireUpdatePosition>();
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
var grid = SystemAPI.GetSingleton<GridData>();
var entityGrid = SystemAPI.GetSingletonEntity<GridData>();
if (SystemAPI.HasComponent<UpdatePoints>(entityGrid) || SystemAPI.HasComponent<CastTag>(entityGrid) ||
SystemAPI.HasComponent<UpdateCheck>(entityGrid))
return;
var ecb = new EntityCommandBuffer(Allocator.Temp);
var converter = new FlatenFloatArray2D(grid.GridSize, grid.CellSize, grid.Center);
var gridLength = grid.GridSize.x * grid.GridSize.y;
var initialCapacity = gridLength < 256 ? gridLength : 256;
var visited = new NativeArray<byte>(gridLength, Allocator.Temp, NativeArrayOptions.ClearMemory);
var addedPoints = new NativeList<ushort>(initialCapacity, Allocator.Temp);
var currentPoints = new NativeList<int>(initialCapacity, Allocator.Temp);
var nextPoints = new NativeList<int>(initialCapacity, Allocator.Temp);
foreach (var (updatePosition, entity) in SystemAPI.Query<RefRO<RequireUpdatePosition>>().WithEntityAccess())
{
var starIndex = converter.GetCellAtPosition(updatePosition.ValueRO.Value);
currentPoints.Clear();
nextPoints.Clear();
if (TryAddPoint(starIndex, visited, ref addedPoints))
currentPoints.Add(starIndex);
for (var radius = 0; radius < UPDATE_RADIUS; radius++)
{
for (var i = 0; i < currentPoints.Length; i++)
{
AddNeighbours(currentPoints[i], grid.GridSize.x, grid.GridSize.y, visited, ref addedPoints,
ref nextPoints);
}
var tempPoints = currentPoints;
currentPoints = nextPoints;
nextPoints = tempPoints;
nextPoints.Clear();
}
ecb.RemoveComponent<RequireUpdatePosition>(entity);
}
if (addedPoints.Length > 0)
{
ecb.AddComponent(entityGrid, new UpdatePoints
{
Indexes = new NativeArray<ushort>(addedPoints.AsArray(), Allocator.Persistent)
});
ecb.AddComponent<CastTag>(entityGrid);
}
ecb.Playback(state.EntityManager);
ecb.Dispose();
visited.Dispose();
currentPoints.Dispose();
nextPoints.Dispose();
addedPoints.Dispose();
}
private bool TryAddPoint(int index, NativeArray<byte> visited, ref NativeList<ushort> addedPoints)
{
if (visited[index] != 0)
return false;
visited[index] = 1;
addedPoints.Add((ushort)index);
return true;
}
private void AddNeighbours(int currentNodeIndex, int width, int height, NativeArray<byte> visited,
ref NativeList<ushort> addedPoints, ref NativeList<int> nextPoints)
{
var pointX = currentNodeIndex % width;
var pointY = currentNodeIndex / width;
for (var yOffset = -1; yOffset <= 1; yOffset++)
{
for (var xOffset = -1; xOffset <= 1; xOffset++)
{
if ((xOffset | yOffset) == 0)
continue;
var neighbourX = pointX + xOffset;
var neighbourY = pointY + yOffset;
if ((uint)neighbourX >= (uint)width || (uint)neighbourY >= (uint)height)
continue;
var neighbourIndex = neighbourY * width + neighbourX;
if (!TryAddPoint(neighbourIndex, visited, ref addedPoints))
continue;
nextPoints.Add(neighbourIndex);
}
}
}
}
}