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
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();
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|