forked from Misaki/GhostEngine
Updated Archetype
This commit is contained in:
@@ -5,17 +5,17 @@ using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ghost.ArcEntities;
|
||||
|
||||
internal unsafe struct Archetype : IDisposable
|
||||
public unsafe struct Archetype : IDisposable
|
||||
{
|
||||
private UnsafeList<Chuck> _chunks;
|
||||
private UnsafeArray<int> _offsets;
|
||||
private UnsafeArray<int> _componentIDs;
|
||||
private UnsafeArray<int> _componentIDToOffset;
|
||||
private int _entityCapacity;
|
||||
private int _maxComponentID;
|
||||
|
||||
private UnsafeList<Chuck> _chunks;
|
||||
private int _entityIdsOffset;
|
||||
|
||||
public int EntityCapacity => _entityCapacity;
|
||||
public int ChunkCount => _chunks.Count;
|
||||
|
||||
public Archetype(ReadOnlySpan<ComponentInfo> components)
|
||||
{
|
||||
@@ -30,19 +30,26 @@ internal unsafe struct Archetype : IDisposable
|
||||
|
||||
// Calculate total size per entity to get an initial capacity estimate
|
||||
var bytesPerEntity = entitySize;
|
||||
_maxComponentID = 0;
|
||||
var maxComponentID = 0;
|
||||
for (var i = 0; i < components.Length; i++)
|
||||
{
|
||||
bytesPerEntity += components[i].size;
|
||||
if (components[i].id > _maxComponentID)
|
||||
if (components[i].id > maxComponentID)
|
||||
{
|
||||
_maxComponentID = components[i].id;
|
||||
maxComponentID = components[i].id;
|
||||
}
|
||||
}
|
||||
|
||||
_maxComponentID = maxComponentID;
|
||||
_entityCapacity = Chuck.CHUNK_SIZE / bytesPerEntity;
|
||||
_offsets = new UnsafeArray<int>(components.Length, Allocator.Persistent);
|
||||
_componentIDToOffset = new UnsafeArray<int>(_maxComponentID + 1, Allocator.Persistent);
|
||||
for (var i = 0; i < _componentIDToOffset.Count; ++i) _componentIDToOffset[i] = -1;
|
||||
|
||||
_componentIDToOffset.AsSpan().Fill(-1);
|
||||
|
||||
var sortedComponents = new ComponentInfo[components.Length];
|
||||
components.CopyTo(sortedComponents);
|
||||
Array.Sort(sortedComponents, (a, b) => b.alignment.CompareTo(a.alignment));
|
||||
|
||||
while (_entityCapacity > 0)
|
||||
{
|
||||
@@ -52,13 +59,13 @@ internal unsafe struct Archetype : IDisposable
|
||||
currentOffset = (currentOffset + entityAlign - 1) & ~(entityAlign - 1);
|
||||
currentOffset += _entityCapacity * entitySize;
|
||||
|
||||
var entityOffset = currentOffset;
|
||||
var tempOffsets = new int[components.Length];
|
||||
_entityIdsOffset = currentOffset;
|
||||
var tempOffsets = stackalloc int[components.Length];
|
||||
|
||||
for (var i = 0; i < components.Length; i++)
|
||||
for (var i = 0; i < sortedComponents.Length; i++)
|
||||
{
|
||||
var size = components[i].size;
|
||||
var align = components[i].alignment;
|
||||
var size = sortedComponents[i].size;
|
||||
var align = sortedComponents[i].alignment;
|
||||
|
||||
currentOffset = (currentOffset + align - 1) & ~(align - 1);
|
||||
tempOffsets[i] = currentOffset;
|
||||
@@ -73,9 +80,10 @@ internal unsafe struct Archetype : IDisposable
|
||||
|
||||
if (fits)
|
||||
{
|
||||
for (var i = 0; i < components.Length; i++)
|
||||
for (var i = 0; i < sortedComponents.Length; i++)
|
||||
{
|
||||
_componentIDToOffset[components[i].id] = tempOffsets[i];
|
||||
_offsets[i] = tempOffsets[i];
|
||||
_componentIDToOffset[sortedComponents[i].id] = tempOffsets[i];
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -85,19 +93,60 @@ internal unsafe struct Archetype : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
public Chuck CreateChunk()
|
||||
internal ref Chuck GetChunkReference(int index)
|
||||
{
|
||||
var chunk = new Chuck(Chuck.CHUNK_SIZE, _entityCapacity);
|
||||
_chunks.Add(chunk);
|
||||
return ref _chunks[index];
|
||||
}
|
||||
|
||||
return chunk;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int GetOffset(int componentId)
|
||||
{
|
||||
if (componentId >= _componentIDToOffset.Count)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _componentIDToOffset[componentId];
|
||||
}
|
||||
|
||||
public void RemoveEntity(int chunkIndex, int rowIndex)
|
||||
{
|
||||
var chunk = _chunks[chunkIndex];
|
||||
int lastIndex = chunk.Count - 1;
|
||||
|
||||
// 1. If we are NOT removing the very last entity, we must swap.
|
||||
if (rowIndex != lastIndex)
|
||||
{
|
||||
// A. We are moving the 'last' entity into the 'row' spot.
|
||||
// We need to know WHO that last entity is so we can update the lookup map.
|
||||
|
||||
var pLastEntity = chunk.GetUnsafePtr() + _entityIdsOffset + (sizeof(Entity) * lastIndex);
|
||||
var lastEntity = *(Entity*)pLastEntity;
|
||||
|
||||
// B. Now we can update the map
|
||||
// World.UpdateLocation(lastEntity.ID, newIndex: rowIndex);
|
||||
|
||||
// C. Perform the memory copy (Swap components)
|
||||
for (var i = 0; i <= _offsets.Count; i++)
|
||||
{
|
||||
var offset = _offsets[i];
|
||||
var compSize = ComponentRegister.GetComponentInfo(i).size;
|
||||
|
||||
var pRow = chunk.GetUnsafePtr() + offset + (compSize * rowIndex);
|
||||
var pLast = chunk.GetUnsafePtr() + offset + (compSize * lastIndex);
|
||||
|
||||
MemoryUtility.MemCpy(pLast, pRow, (nuint)compSize);
|
||||
}
|
||||
}
|
||||
|
||||
chunk.Count--;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public UnsafeArray<T> GetComponentArray<T>(int chunkIndex)
|
||||
where T : unmanaged
|
||||
{
|
||||
var id = ComponentType<T>.id;
|
||||
var id = ComponentTypeID<T>.value;
|
||||
if (id >= _componentIDToOffset.Count)
|
||||
{
|
||||
return default;
|
||||
|
||||
Reference in New Issue
Block a user