diff --git a/src/ComponentDepot.cs b/src/ComponentDepot.cs index 38eaef6..482214e 100644 --- a/src/ComponentDepot.cs +++ b/src/ComponentDepot.cs @@ -37,7 +37,7 @@ namespace MoonTools.ECS { // TODO: is it possible to optimize this? Register(); - return storages[typeof(TComponent)] as ComponentStorage; + return (ComponentStorage) storages[typeof(TComponent)]; } public bool Some() where TComponent : struct diff --git a/src/EntityComponentReader.cs b/src/EntityComponentReader.cs index 1c65d05..5449d95 100644 --- a/src/EntityComponentReader.cs +++ b/src/EntityComponentReader.cs @@ -60,22 +60,22 @@ namespace MoonTools.ECS return EntityStorage.Exists(entity); } - protected IEnumerable Relations() + protected IEnumerable<(Entity, Entity, TRelationKind)> Relations() where TRelationKind : struct { return RelationDepot.Relations(); } - protected bool Related(in Entity a, in Entity b) + protected bool Related(in Entity a, in Entity b) where TRelationKind : struct { return RelationDepot.Related(a.ID, b.ID); } - protected IEnumerable RelatedToA(in Entity entity) + protected IEnumerable<(Entity, TRelationKind)> RelatedToA(in Entity entity) where TRelationKind : struct { return RelationDepot.RelatedToA(entity.ID); } - protected IEnumerable RelatedToB(in Entity entity) + protected IEnumerable<(Entity, TRelationKind)> RelatedToB(in Entity entity) where TRelationKind : struct { return RelationDepot.RelatedToB(entity.ID); } diff --git a/src/Relation.cs b/src/Relation.cs index 3b0850c..165aca6 100644 --- a/src/Relation.cs +++ b/src/Relation.cs @@ -2,7 +2,7 @@ namespace MoonTools.ECS { - public struct Relation : IEquatable + internal struct Relation : IEquatable { public Entity A { get; } public Entity B { get; } @@ -26,12 +26,12 @@ namespace MoonTools.ECS public bool Equals(Relation other) { - return A.Equals(other.A) && B.Equals(other.B); + return A.ID == other.A.ID && B.ID == other.B.ID; } public override int GetHashCode() { - return HashCode.Combine(A, B); + return HashCode.Combine(A.ID, B.ID); } } } diff --git a/src/RelationDepot.cs b/src/RelationDepot.cs index 1ae4ab9..82b7114 100644 --- a/src/RelationDepot.cs +++ b/src/RelationDepot.cs @@ -7,26 +7,31 @@ namespace MoonTools.ECS { private Dictionary storages = new Dictionary(); - private RelationStorage Lookup() + private void Register() where TRelationKind : struct { - return storages[typeof(TRelationKind)]; + if (!storages.ContainsKey(typeof(TRelationKind))) + { + storages.Add(typeof(TRelationKind), new RelationStorage()); + } } - public void Register() + private RelationStorage Lookup() where TRelationKind : struct { - storages[typeof(TRelationKind)] = new RelationStorage(); + Register(); + return (RelationStorage) storages[typeof(TRelationKind)]; } - public void Add(Relation relation) + public void Add(Relation relation, TRelationKind relationData) where TRelationKind : struct { - Lookup().Add(relation); + Lookup().Add(relation, relationData); } - public void Remove(Relation relation) + public void Remove(Relation relation) where TRelationKind : struct { Lookup().Remove(relation); } + // FIXME: optimize this public void OnEntityDestroy(int entityID) { foreach (var storage in storages.Values) @@ -35,22 +40,22 @@ namespace MoonTools.ECS } } - public IEnumerable Relations() + public IEnumerable<(Entity, Entity, TRelationKind)> Relations() where TRelationKind : struct { return Lookup().All(); } - public bool Related(int idA, int idB) + public bool Related(int idA, int idB) where TRelationKind : struct { return Lookup().Has(new Relation(idA, idB)); } - public IEnumerable RelatedToA(int entityID) + public IEnumerable<(Entity, TRelationKind)> RelatedToA(int entityID) where TRelationKind : struct { return Lookup().RelatedToA(entityID); } - public IEnumerable RelatedToB(int entityID) + public IEnumerable<(Entity, TRelationKind)> RelatedToB(int entityID) where TRelationKind : struct { return Lookup().RelatedToB(entityID); } diff --git a/src/RelationStorage.cs b/src/RelationStorage.cs index 872f2d7..6f82074 100644 --- a/src/RelationStorage.cs +++ b/src/RelationStorage.cs @@ -2,24 +2,31 @@ namespace MoonTools.ECS { - internal class RelationStorage + internal abstract class RelationStorage { - private HashSet relations = new HashSet(16); + public abstract void OnEntityDestroy(int entityID); + } + + // Relation is the two entities, A related to B. + // TRelation is the data attached to the relation. + internal class RelationStorage : RelationStorage where TRelation : struct + { + private Dictionary relations = new Dictionary(16); private Dictionary> entitiesRelatedToA = new Dictionary>(16); private Dictionary> entitiesRelatedToB = new Dictionary>(16); private Stack> listPool = new Stack>(); - public IEnumerable All() + public IEnumerable<(Entity, Entity, TRelation)> All() { - foreach (var relation in relations) + foreach (var relationData in relations) { - yield return relation; + yield return (relationData.Key.A, relationData.Key.B, relationData.Value); } } - public void Add(Relation relation) + public void Add(Relation relation, TRelation relationData) { - if (relations.Contains(relation)) { return; } + if (relations.ContainsKey(relation)) { return; } var idA = relation.A.ID; var idB = relation.B.ID; @@ -36,32 +43,35 @@ namespace MoonTools.ECS } entitiesRelatedToB[idB].Add(idA); - relations.Add(relation); + relations.Add(relation, relationData); } public bool Has(Relation relation) { - return relations.Contains(relation); + return relations.ContainsKey(relation); } - public IEnumerable RelatedToA(int entityID) + // FIXME: is there a more descriptive name for these? + public IEnumerable<(Entity, TRelation)> RelatedToA(int entityID) { if (entitiesRelatedToA.ContainsKey(entityID)) { foreach (var id in entitiesRelatedToA[entityID]) { - yield return new Entity(id); + var relation = new Relation(entityID, id); + yield return (relation.B, relations[relation]); } } } - public IEnumerable RelatedToB(int entityID) + public IEnumerable<(Entity, TRelation)> RelatedToB(int entityID) { if (entitiesRelatedToB.ContainsKey(entityID)) { foreach (var id in entitiesRelatedToB[entityID]) { - yield return new Entity(id); + var relation = new Relation(id, entityID); + yield return (relation.A, relations[relation]); } } } @@ -81,19 +91,13 @@ namespace MoonTools.ECS return relations.Remove(relation); } - // this exists so we don't recurse in OnEntityDestroy - private bool DestroyRemove(Relation relation) - { - return relations.Remove(relation); - } - - public void OnEntityDestroy(int entityID) + public override void OnEntityDestroy(int entityID) { if (entitiesRelatedToA.ContainsKey(entityID)) { foreach (var entityB in entitiesRelatedToA[entityID]) { - DestroyRemove(new Relation(entityID, entityB)); + Remove(new Relation(entityID, entityB)); } ReturnHashSetToPool(entitiesRelatedToA[entityID]); @@ -104,7 +108,7 @@ namespace MoonTools.ECS { foreach (var entityA in entitiesRelatedToB[entityID]) { - DestroyRemove(new Relation(entityA, entityID)); + Remove(new Relation(entityA, entityID)); } ReturnHashSetToPool(entitiesRelatedToB[entityID]); @@ -124,6 +128,7 @@ namespace MoonTools.ECS private void ReturnHashSetToPool(HashSet hashSet) { + hashSet.Clear(); listPool.Push(hashSet); } } diff --git a/src/System.cs b/src/System.cs index 2cefe1d..66eee93 100644 --- a/src/System.cs +++ b/src/System.cs @@ -76,12 +76,12 @@ namespace MoonTools.ECS MessageDepot.Add(message); } - protected void Relate(in Entity entityA, in Entity entityB) + protected void Relate(in Entity entityA, in Entity entityB, TRelationKind relationData) where TRelationKind : struct { - RelationDepot.Add(new Relation(entityA, entityB)); + RelationDepot.Add(new Relation(entityA, entityB), relationData); } - protected void Unrelate(in Entity entityA, in Entity entityB) + protected void Unrelate(in Entity entityA, in Entity entityB) where TRelationKind : struct { RelationDepot.Remove(new Relation(entityA, entityB)); } diff --git a/src/World.cs b/src/World.cs index d228b33..8e9e97d 100644 --- a/src/World.cs +++ b/src/World.cs @@ -22,11 +22,6 @@ renderer.RegisterRelationDepot(RelationDepot); } - public void AddRelationKind() - { - RelationDepot.Register(); - } - public Entity CreateEntity() { return EntityStorage.Create();