You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

130 lines
3.6 KiB

2 years ago
using System;
using Unity.Collections;
using System.Diagnostics;
namespace GameCore.TinyECS
{
public struct EntityCollection<TEnum> : IDisposable where TEnum : unmanaged
{
private struct Buffer
{
public int index;
public int generation;
}
private NativeList<Buffer> entityBuffer;
private NativeList<int> entityIndexToDataIndex;
private TEnum entityType;
public EntityCollection(TEnum type, int capacity, Allocator allocator)
{
entityType = type;
entityBuffer = new (capacity, allocator);
entityIndexToDataIndex = new (capacity, allocator);
}
public void Dispose()
{
entityBuffer.Dispose();
entityIndexToDataIndex.Dispose();
}
public int Count => entityBuffer.Length;
public Entity<TEnum> this[int index]
{
get
{
var buf = entityBuffer[index];
return new(entityType, buf.index, buf.generation);
}
}
public int Add(Entity<TEnum> entity)
{
CheckEntityType(entity);
var dataIndex = entityBuffer.Length;
var oldEntityCount = entityIndexToDataIndex.Length;
if (entity.index >= oldEntityCount)
{
entityIndexToDataIndex.Resize(entity.index + 1, NativeArrayOptions.UninitializedMemory);
for (int i = oldEntityCount, e = entity.index - 1; i < e; ++i)
{
entityIndexToDataIndex[i] = -1;
}
}
entityIndexToDataIndex[entity.index] = dataIndex;
entityBuffer.Add(new Buffer{index = entity.index, generation = entity.generation });
return dataIndex;
}
public bool TryGetIndex(Entity<TEnum> entity, out int index)
{
CheckEntityType(entity);
index = 0;
if (entity.index >= entityIndexToDataIndex.Length)
{
return false;
}
index = entityIndexToDataIndex[entity.index];
if (index < 0 || index >= entityBuffer.Length)
{
return false;
}
var buf = entityBuffer[index];
return buf.index == entity.index && buf.generation == entity.generation;
}
public bool Remove(Entity<TEnum> entity, out int index, out bool removeFromBack)
{
CheckEntityType(entity);
if (!TryGetIndex(entity, out index))
{
removeFromBack = false;
return false;
}
removeFromBack = RemoveInternal(entity, index);
return true;
}
private bool RemoveInternal(Entity<TEnum> entity, int index)
{
entityIndexToDataIndex[entity.index] = -1;
var backIndex = entityBuffer.Length - 1;
if (index == backIndex)
{
entityBuffer.Resize(backIndex, NativeArrayOptions.UninitializedMemory);
return true;
}
var backBuf = entityBuffer[backIndex];
entityBuffer.RemoveAtSwapBack(index);
entityIndexToDataIndex[backBuf.index] = index;
return false;
}
[Conditional("DEBUG")]
void CheckEntityType(Entity<TEnum> entity)
{
if (!entity.type.Equals(entityType))
throw new Exception($"Wrong entity type: {entity.type}");
}
public void Clear()
{
entityBuffer.Clear();
entityIndexToDataIndex.Clear();
}
}
}