From 5a670fa36c51c7f841cf275e4c8b1085da951f3b Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Fri, 20 Oct 2023 01:17:03 -0700 Subject: [PATCH] entity iteration pattern --- src/Rev2/Archetype.cs | 2 +- src/Rev2/ComponentId.cs | 10 ++++- src/Rev2/World.cs | 91 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 95 insertions(+), 8 deletions(-) diff --git a/src/Rev2/Archetype.cs b/src/Rev2/Archetype.cs index e5f8a16..ff3a435 100644 --- a/src/Rev2/Archetype.cs +++ b/src/Rev2/Archetype.cs @@ -8,7 +8,7 @@ namespace MoonTools.ECS.Rev2 public ArchetypeId Id { get; private set; } public List Components = new List(); public List RowToEntity = new List(); - public Dictionary Edges = new Dictionary(); + public SortedDictionary Edges = new SortedDictionary(); public int Count; diff --git a/src/Rev2/ComponentId.cs b/src/Rev2/ComponentId.cs index b2b24b8..5e11e0e 100644 --- a/src/Rev2/ComponentId.cs +++ b/src/Rev2/ComponentId.cs @@ -1,4 +1,12 @@ +using System; + namespace MoonTools.ECS.Rev2 { - public readonly record struct ComponentId(int Id) : IHasId; + public readonly record struct ComponentId(int Id) : IHasId, IComparable + { + public int CompareTo(ComponentId other) + { + return Id.CompareTo(other.Id); + } + } } diff --git a/src/Rev2/World.cs b/src/Rev2/World.cs index 2fccc9a..b6ac0a0 100644 --- a/src/Rev2/World.cs +++ b/src/Rev2/World.cs @@ -28,6 +28,8 @@ namespace MoonTools.ECS.Rev2 private bool IsDisposed; + public delegate void RefAction(ref T1 arg1, ref T2 arg2); + public World() { // 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 - private ComponentId RegisterComponent() where T : unmanaged + private void RegisterComponent() where T : unmanaged { var componentId = ComponentIdAssigner.Assign(); TypeToComponentId.Add(typeof(T), componentId); ComponentIndex.Add(componentId, new Dictionary()); ElementSizes.Add(componentId, Unsafe.SizeOf()); - return componentId; } - public ComponentId GetComponentId() where T : unmanaged + private void TryRegisterComponentId() where T : unmanaged { if (!TypeToComponentId.TryGetValue(typeof(T), out var componentId)) { - return RegisterComponent(); + RegisterComponent(); } + } - return componentId; + private ComponentId GetComponentId() where T : unmanaged + { + return TypeToComponentId[typeof(T)]; + } + + internal ArchetypeRecord GetArchetypeRecord(Archetype archetype) where T : unmanaged + { + var componentId = GetComponentId(); + return ComponentIndex[componentId][archetype.Id]; } public bool HasComponent(EntityId entityId) where T : unmanaged @@ -111,7 +121,28 @@ namespace MoonTools.ECS.Rev2 return ((T*) column.Elements)[record.Row]; } - public void AddComponent(EntityId entityId, T component) where T : unmanaged + public unsafe void SetComponent(EntityId entityId, T component) where T : unmanaged + { + TryRegisterComponentId(); + var componentId = GetComponentId(); + + if (HasComponent(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(EntityId entityId, T component) where T : unmanaged { Archetype? nextArchetype; @@ -247,6 +278,54 @@ namespace MoonTools.ECS.Rev2 from.Count -= 1; } + public unsafe void ForEachEntity(ArchetypeSignature signature, RefAction 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 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) { if (!IsDisposed)