entity iteration pattern

rev2
cosmonaut 2023-10-20 01:17:03 -07:00
parent 6173b05ff6
commit 5a670fa36c
3 changed files with 95 additions and 8 deletions

View File

@ -8,7 +8,7 @@ namespace MoonTools.ECS.Rev2
public ArchetypeId Id { get; private set; } public ArchetypeId Id { get; private set; }
public List<Column> Components = new List<Column>(); public List<Column> Components = new List<Column>();
public List<EntityId> RowToEntity = new List<EntityId>(); public List<EntityId> RowToEntity = new List<EntityId>();
public Dictionary<ComponentId, ArchetypeEdge> Edges = new Dictionary<ComponentId, ArchetypeEdge>(); public SortedDictionary<ComponentId, ArchetypeEdge> Edges = new SortedDictionary<ComponentId, ArchetypeEdge>();
public int Count; public int Count;

View File

@ -1,4 +1,12 @@
using System;
namespace MoonTools.ECS.Rev2 namespace MoonTools.ECS.Rev2
{ {
public readonly record struct ComponentId(int Id) : IHasId; public readonly record struct ComponentId(int Id) : IHasId, IComparable<ComponentId>
{
public int CompareTo(ComponentId other)
{
return Id.CompareTo(other.Id);
}
}
} }

View File

@ -28,6 +28,8 @@ namespace MoonTools.ECS.Rev2
private bool IsDisposed; private bool IsDisposed;
public delegate void RefAction<T1, T2>(ref T1 arg1, ref T2 arg2);
public World() public World()
{ {
// Create the Empty Archetype // Create the Empty Archetype
@ -64,23 +66,31 @@ namespace MoonTools.ECS.Rev2
} }
// FIXME: would be much more efficient to do all this at load time somehow // FIXME: would be much more efficient to do all this at load time somehow
private ComponentId RegisterComponent<T>() where T : unmanaged private void RegisterComponent<T>() where T : unmanaged
{ {
var componentId = ComponentIdAssigner.Assign(); var componentId = ComponentIdAssigner.Assign();
TypeToComponentId.Add(typeof(T), componentId); TypeToComponentId.Add(typeof(T), componentId);
ComponentIndex.Add(componentId, new Dictionary<ArchetypeId, ArchetypeRecord>()); ComponentIndex.Add(componentId, new Dictionary<ArchetypeId, ArchetypeRecord>());
ElementSizes.Add(componentId, Unsafe.SizeOf<T>()); ElementSizes.Add(componentId, Unsafe.SizeOf<T>());
return componentId;
} }
public ComponentId GetComponentId<T>() where T : unmanaged private void TryRegisterComponentId<T>() where T : unmanaged
{ {
if (!TypeToComponentId.TryGetValue(typeof(T), out var componentId)) if (!TypeToComponentId.TryGetValue(typeof(T), out var componentId))
{ {
return RegisterComponent<T>(); RegisterComponent<T>();
} }
}
return componentId; private ComponentId GetComponentId<T>() where T : unmanaged
{
return TypeToComponentId[typeof(T)];
}
internal ArchetypeRecord GetArchetypeRecord<T>(Archetype archetype) where T : unmanaged
{
var componentId = GetComponentId<T>();
return ComponentIndex[componentId][archetype.Id];
} }
public bool HasComponent<T>(EntityId entityId) where T : unmanaged public bool HasComponent<T>(EntityId entityId) where T : unmanaged
@ -111,7 +121,28 @@ namespace MoonTools.ECS.Rev2
return ((T*) column.Elements)[record.Row]; return ((T*) column.Elements)[record.Row];
} }
public void AddComponent<T>(EntityId entityId, T component) where T : unmanaged public unsafe void SetComponent<T>(EntityId entityId, T component) where T : unmanaged
{
TryRegisterComponentId<T>();
var componentId = GetComponentId<T>();
if (HasComponent<T>(entityId))
{
var record = EntityIndex[entityId];
var archetype = record.Archetype;
var archetypes = ComponentIndex[componentId];
var archetypeRecord = archetypes[archetype.Id];
var column = archetype.Components[archetypeRecord.ColumnIndex];
((T*) column.Elements)[record.Row] = component;
}
else
{
AddComponent(entityId, component);
}
}
private void AddComponent<T>(EntityId entityId, T component) where T : unmanaged
{ {
Archetype? nextArchetype; Archetype? nextArchetype;
@ -247,6 +278,54 @@ namespace MoonTools.ECS.Rev2
from.Count -= 1; from.Count -= 1;
} }
public unsafe void ForEachEntity<T1, T2>(ArchetypeSignature signature, RefAction<T1, T2> rowAction) where T1 : unmanaged where T2 : unmanaged
{
var archetype = ArchetypeIndex[signature];
var componentIdOne = signature[0];
var columnIndexOne = ComponentIndex[componentIdOne][archetype.Id].ColumnIndex;
var columnOneElements = archetype.Components[columnIndexOne].Elements;
var componentIdTwo = signature[1];
var columnIndexTwo = ComponentIndex[componentIdTwo][archetype.Id].ColumnIndex;
var columnTwoElements = archetype.Components[columnIndexTwo].Elements;
for (int i = 0; i < archetype.Count; i += 1)
{
rowAction(ref ((T1*) columnOneElements)[i], ref ((T2*) columnTwoElements)[i]);
}
foreach (var edge in archetype.Edges.Values)
{
if (edge.Add != archetype)
{
ForEachEntity(edge.Add.Signature, rowAction);
}
}
}
/*
public void ForEachEntity(ArchetypeSignature signature, Action<Entity> rowAction)
{
var archetype = ArchetypeIndex[signature];
for (int i = 0; i < archetype.Count; i += 1)
{
var entity = new Entity(this, archetype, i, archetype.RowToEntity[i]);
rowAction(entity);
}
// recursion might get too hairy here
foreach (var edge in archetype.Edges.Values)
{
if (edge.Add != archetype)
{
ForEachEntity(edge.Add.Signature, rowAction);
}
}
}
*/
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)
{ {
if (!IsDisposed) if (!IsDisposed)