From 8d1274cba0a50c412407bc13f2fb940c59d537c1 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Wed, 7 Dec 2022 13:53:23 -0800 Subject: [PATCH] more untyped storage granularity --- src/ComponentDepot.cs | 23 +++++++++++++++++------ src/ComponentStorage.cs | 32 +++++++++++++++++++++++++------- src/DebugSystem.cs | 11 ++++------- src/RelationDepot.cs | 16 ++++++++-------- src/RelationStorage.cs | 37 ++++++++++++++++++++----------------- src/Snapshot.cs | 12 ++++++------ src/World.cs | 2 +- 7 files changed, 81 insertions(+), 52 deletions(-) diff --git a/src/ComponentDepot.cs b/src/ComponentDepot.cs index 04e1d03..6f746fa 100644 --- a/src/ComponentDepot.cs +++ b/src/ComponentDepot.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Runtime.CompilerServices; namespace MoonTools.ECS @@ -57,8 +58,6 @@ namespace MoonTools.ECS Lookup().Set(entityID, component); } - - public Entity GetSingletonEntity() where TComponent : unmanaged { return Lookup().FirstEntity(); @@ -92,14 +91,12 @@ namespace MoonTools.ECS // these methods used to implement snapshots, templates, and debugging - // FIXME: use unsafe pointers instead of object - internal object UntypedGet(int entityID, int componentTypeIndex) + internal unsafe void* UntypedGet(int entityID, int componentTypeIndex) { return storages[componentTypeIndex].UntypedGet(entityID); } - // FIXME: use unsafe pointers instead of object - internal void Set(int entityID, int componentTypeIndex, object component) + internal unsafe void Set(int entityID, int componentTypeIndex, void* component) { storages[componentTypeIndex].Set(entityID, component); } @@ -114,5 +111,19 @@ namespace MoonTools.ECS } } } + + // this method is used to iterate components of an entity, only for use with a debug inspector + +#if DEBUG + public object Debug_Get(int entityID, int componentTypeIndex) + { + return storages[componentTypeIndex].Debug_Get(entityID); + } + + public IEnumerable Debug_GetEntityIDs(int componentTypeIndex) + { + return storages[componentTypeIndex].Debug_GetEntityIDs(); + } +#endif } } diff --git a/src/ComponentStorage.cs b/src/ComponentStorage.cs index bd3fd66..5ea989f 100644 --- a/src/ComponentStorage.cs +++ b/src/ComponentStorage.cs @@ -1,19 +1,22 @@ using System; using System.Collections.Generic; -using System.Runtime.InteropServices; namespace MoonTools.ECS { internal abstract class ComponentStorage { - internal abstract void Set(int entityID, object component); + internal abstract unsafe void Set(int entityID, void* component); public abstract bool Remove(int entityID); public abstract void Clear(); // used for debugging and template instantiation - internal abstract object UntypedGet(int entityID); + internal abstract unsafe void* UntypedGet(int entityID); // used to create correctly typed storage on snapshot public abstract ComponentStorage CreateStorage(); +#if DEBUG + internal abstract object Debug_Get(int entityID); + internal abstract IEnumerable Debug_GetEntityIDs(); +#endif } internal class ComponentStorage : ComponentStorage where TComponent : unmanaged @@ -33,9 +36,12 @@ namespace MoonTools.ECS return ref components[entityIDToStorageIndex[entityID]]; } - internal override object UntypedGet(int entityID) + internal override unsafe void* UntypedGet(int entityID) { - return components[entityIDToStorageIndex[entityID]]; + fixed (void* p = &components[entityIDToStorageIndex[entityID]]) + { + return p; + } } public ref readonly TComponent GetFirst() @@ -69,9 +75,9 @@ namespace MoonTools.ECS components[entityIDToStorageIndex[entityID]] = component; } - internal override void Set(int entityID, object component) + internal override unsafe void Set(int entityID, void* component) { - Set(entityID, (TComponent) component); + Set(entityID, *((TComponent*) component)); } // Returns true if the entity had this component. @@ -127,5 +133,17 @@ namespace MoonTools.ECS { return new ComponentStorage(); } + +#if DEBUG + internal override object Debug_Get(int entityID) + { + return components[entityIDToStorageIndex[entityID]]; + } + + internal override IEnumerable Debug_GetEntityIDs() + { + return entityIDToStorageIndex.Keys; + } +#endif } } diff --git a/src/DebugSystem.cs b/src/DebugSystem.cs index 36aada6..de9027a 100644 --- a/src/DebugSystem.cs +++ b/src/DebugSystem.cs @@ -9,27 +9,24 @@ namespace MoonTools.ECS { public abstract class DebugSystem : System { - private Dictionary singleComponentFilters = new Dictionary(); - protected DebugSystem(World world) : base(world) { } - protected IEnumerable Debug_GetAllComponents(Entity entity) + protected IEnumerable Debug_GetAllComponents(Entity entity) { foreach (var typeIndex in EntityStorage.ComponentTypeIndices(entity.ID)) { - yield return ComponentDepot.UntypedGet(entity.ID, typeIndex); + yield return ComponentDepot.Debug_Get(entity.ID, typeIndex); } } protected IEnumerable Debug_GetEntities(Type componentType) { - if (!singleComponentFilters.ContainsKey(componentType)) + foreach (var entityID in ComponentDepot.Debug_GetEntityIDs(ComponentTypeIndices.GetIndex(componentType))) { - singleComponentFilters.Add(componentType, new Filter(FilterStorage, new HashSet(ComponentTypeIndices.GetIndex(componentType)), new HashSet())); + yield return new Entity(entityID); } - return singleComponentFilters[componentType].Entities; } protected IEnumerable Debug_SearchComponentType(string typeString) diff --git a/src/RelationDepot.cs b/src/RelationDepot.cs index e3b9225..4baa35c 100644 --- a/src/RelationDepot.cs +++ b/src/RelationDepot.cs @@ -103,24 +103,24 @@ namespace MoonTools.ECS // untyped methods used for destroying and snapshots - public void Set(int entityA, int entityB, int relationTypeIndex, object relationData) + public unsafe void Set(int entityA, int entityB, int relationTypeIndex, void* relationData) { storages[relationTypeIndex].Set(entityA, entityB, relationData); } + public unsafe void* Get(int relationTypeIndex, int relationStorageIndex) + { + return storages[relationTypeIndex].Get(relationStorageIndex); + } + public void UnrelateAll(int entityID, int relationTypeIndex) { storages[relationTypeIndex].UnrelateAll(entityID); } - public IEnumerable<(int, object)> InRelations(int entityID, int relationTypeIndex) + public IEnumerable<(int, int)> OutRelationIndices(int entityID, int relationTypeIndex) { - return storages[relationTypeIndex].UntypedInRelations(entityID); - } - - public IEnumerable<(int, object)> OutRelations(int entityID, int relationTypeIndex) - { - return storages[relationTypeIndex].UntypedOutRelations(entityID); + return storages[relationTypeIndex].OutRelationIndices(entityID); } public void Clear() diff --git a/src/RelationStorage.cs b/src/RelationStorage.cs index 9a2a887..c7ed957 100644 --- a/src/RelationStorage.cs +++ b/src/RelationStorage.cs @@ -5,11 +5,10 @@ namespace MoonTools.ECS { internal abstract class RelationStorage { - public abstract void Set(int entityA, int entityB, object relationData); + public abstract unsafe void Set(int entityA, int entityB, void* relationData); + public abstract unsafe void* Get(int relationStorageIndex); public abstract void UnrelateAll(int entityID); - public abstract IEnumerable<(int, object)> UntypedInRelations(int entityID); - public abstract IEnumerable<(int, object)> UntypedOutRelations(int entityID); - // used to create correctly typed storage on snapshot + public abstract IEnumerable<(int, int)> OutRelationIndices(int entityID); public abstract RelationStorage CreateStorage(); public abstract void Clear(); } @@ -208,9 +207,17 @@ namespace MoonTools.ECS // untyped methods used for internal implementation - public override void Set(int entityA, int entityB, object relationData) + public override unsafe void Set(int entityA, int entityB, void* relationData) { - Set(new Relation(entityA, entityB), (TRelation) relationData); + Set(new Relation(entityA, entityB), *((TRelation*) relationData)); + } + + public override unsafe void* Get(int relationStorageIndex) + { + fixed (void* p = &relations[relationStorageIndex]) + { + return p; + } } public override void UnrelateAll(int entityID) @@ -238,19 +245,15 @@ namespace MoonTools.ECS } } - public override IEnumerable<(int, object)> UntypedInRelations(int entityID) + public override IEnumerable<(int, int)> OutRelationIndices(int entityID) { - foreach (var (entity, relationData) in InRelations(entityID)) + if (outRelations.ContainsKey(entityID)) { - yield return (entity.ID, relationData); - } - } - - public override IEnumerable<(int, object)> UntypedOutRelations(int entityID) - { - foreach (var (entity, relationData) in OutRelations(entityID)) - { - yield return (entity.ID, relationData); + foreach (var id in outRelations[entityID]) + { + var relation = new Relation(entityID, id); + yield return (id, indices[relation]); + } } } diff --git a/src/Snapshot.cs b/src/Snapshot.cs index 52ec53f..6c8be13 100644 --- a/src/Snapshot.cs +++ b/src/Snapshot.cs @@ -23,7 +23,7 @@ namespace MoonTools.ECS SnapshotRelationDepot = new RelationDepot(World.RelationTypeIndices); } - public void Take(Filter filter) + public unsafe void Take(Filter filter) { Clear(); Filter = filter; @@ -50,7 +50,7 @@ namespace MoonTools.ECS { SnapshotEntityStorage.AddRelationKind(snapshotEntityID, relationTypeIndex); - foreach (var (otherEntityID, relationData) in World.RelationDepot.OutRelations(worldEntity.ID, relationTypeIndex)) + foreach (var (otherEntityID, relationStorageIndex) in World.RelationDepot.OutRelationIndices(worldEntity.ID, relationTypeIndex)) { #if DEBUG if (!World.FilterStorage.CheckSatisfied(otherEntityID, Filter.Signature)) @@ -60,13 +60,13 @@ namespace MoonTools.ECS #endif var otherSnapshotID = WorldToSnapshotID[otherEntityID]; SnapshotEntityStorage.AddRelationKind(otherSnapshotID, relationTypeIndex); - SnapshotRelationDepot.Set(snapshotEntityID, otherSnapshotID, relationTypeIndex, relationData); + SnapshotRelationDepot.Set(snapshotEntityID, otherSnapshotID, relationTypeIndex, World.RelationDepot.Get(relationTypeIndex, relationStorageIndex)); } } } } - public void Restore() + public unsafe void Restore() { if (Filter == null) { @@ -99,10 +99,10 @@ namespace MoonTools.ECS { World.EntityStorage.AddRelationKind(worldID, relationTypeIndex); - foreach (var (otherEntityID, relationData) in SnapshotRelationDepot.OutRelations(i, relationTypeIndex)) + foreach (var (otherEntityID, relationStorageIndex) in SnapshotRelationDepot.OutRelationIndices(i, relationTypeIndex)) { var otherEntityWorldID = SnapshotToWorldID[otherEntityID]; - World.RelationDepot.Set(worldID, otherEntityWorldID, relationTypeIndex, relationData); + World.RelationDepot.Set(worldID, otherEntityWorldID, relationTypeIndex, SnapshotRelationDepot.Get(relationTypeIndex, relationStorageIndex)); } } } diff --git a/src/World.cs b/src/World.cs index 85873c0..17f487f 100644 --- a/src/World.cs +++ b/src/World.cs @@ -59,7 +59,7 @@ namespace MoonTools.ECS ComponentDepot.Register(componentTypeIndex); } - public Entity Instantiate(in Template template) + public unsafe Entity Instantiate(in Template template) { var entity = EntityStorage.Create();