MoonTools.ECS/src/RelationStorage.cs

136 lines
3.3 KiB
C#
Raw Normal View History

2022-04-08 05:52:03 +00:00
using System.Collections.Generic;
2022-04-06 19:53:50 +00:00
namespace MoonTools.ECS
{
2022-04-19 19:35:21 +00:00
internal abstract class RelationStorage
2022-04-06 19:53:50 +00:00
{
2022-04-19 19:35:21 +00:00
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<TRelation> : RelationStorage where TRelation : struct
{
private Dictionary<Relation, TRelation> relations = new Dictionary<Relation, TRelation>(16);
2022-04-06 19:53:50 +00:00
private Dictionary<int, HashSet<int>> entitiesRelatedToA = new Dictionary<int, HashSet<int>>(16);
private Dictionary<int, HashSet<int>> entitiesRelatedToB = new Dictionary<int, HashSet<int>>(16);
private Stack<HashSet<int>> listPool = new Stack<HashSet<int>>();
2022-04-19 19:35:21 +00:00
public IEnumerable<(Entity, Entity, TRelation)> All()
2022-04-06 19:53:50 +00:00
{
2022-04-19 19:35:21 +00:00
foreach (var relationData in relations)
2022-04-06 19:53:50 +00:00
{
2022-04-19 19:35:21 +00:00
yield return (relationData.Key.A, relationData.Key.B, relationData.Value);
2022-04-06 19:53:50 +00:00
}
}
2022-04-19 19:35:21 +00:00
public void Add(Relation relation, TRelation relationData)
2022-04-06 19:53:50 +00:00
{
2022-04-19 19:35:21 +00:00
if (relations.ContainsKey(relation)) { return; }
2022-04-07 03:08:28 +00:00
2022-04-06 19:53:50 +00:00
var idA = relation.A.ID;
var idB = relation.B.ID;
if (!entitiesRelatedToA.ContainsKey(idA))
{
entitiesRelatedToA[idA] = AcquireHashSetFromPool();
}
entitiesRelatedToA[idA].Add(idB);
if (!entitiesRelatedToB.ContainsKey(idB))
{
entitiesRelatedToB[idB] = AcquireHashSetFromPool();
}
entitiesRelatedToB[idB].Add(idA);
2022-04-19 19:35:21 +00:00
relations.Add(relation, relationData);
2022-04-06 19:53:50 +00:00
}
2022-04-07 03:08:28 +00:00
public bool Has(Relation relation)
{
2022-04-19 19:35:21 +00:00
return relations.ContainsKey(relation);
2022-04-07 03:08:28 +00:00
}
2022-04-19 19:35:21 +00:00
// FIXME: is there a more descriptive name for these?
public IEnumerable<(Entity, TRelation)> RelatedToA(int entityID)
2022-04-06 19:53:50 +00:00
{
if (entitiesRelatedToA.ContainsKey(entityID))
{
foreach (var id in entitiesRelatedToA[entityID])
{
2022-04-19 19:35:21 +00:00
var relation = new Relation(entityID, id);
yield return (relation.B, relations[relation]);
2022-04-06 19:53:50 +00:00
}
}
}
2022-04-19 19:35:21 +00:00
public IEnumerable<(Entity, TRelation)> RelatedToB(int entityID)
2022-04-06 19:53:50 +00:00
{
if (entitiesRelatedToB.ContainsKey(entityID))
{
foreach (var id in entitiesRelatedToB[entityID])
{
2022-04-19 19:35:21 +00:00
var relation = new Relation(id, entityID);
yield return (relation.A, relations[relation]);
2022-04-06 19:53:50 +00:00
}
}
}
public bool Remove(Relation relation)
{
if (entitiesRelatedToA.ContainsKey(relation.A.ID))
{
entitiesRelatedToA[relation.A.ID].Remove(relation.B.ID);
}
if (entitiesRelatedToB.ContainsKey(relation.B.ID))
{
entitiesRelatedToB[relation.B.ID].Remove(relation.A.ID);
}
return relations.Remove(relation);
}
2022-04-19 19:35:21 +00:00
public override void OnEntityDestroy(int entityID)
2022-04-06 19:53:50 +00:00
{
if (entitiesRelatedToA.ContainsKey(entityID))
{
foreach (var entityB in entitiesRelatedToA[entityID])
{
2022-04-19 19:35:21 +00:00
Remove(new Relation(entityID, entityB));
2022-04-06 19:53:50 +00:00
}
ReturnHashSetToPool(entitiesRelatedToA[entityID]);
entitiesRelatedToA.Remove(entityID);
}
if (entitiesRelatedToB.ContainsKey(entityID))
{
foreach (var entityA in entitiesRelatedToB[entityID])
{
2022-04-19 19:35:21 +00:00
Remove(new Relation(entityA, entityID));
2022-04-06 19:53:50 +00:00
}
ReturnHashSetToPool(entitiesRelatedToB[entityID]);
entitiesRelatedToB.Remove(entityID);
}
}
private HashSet<int> AcquireHashSetFromPool()
{
if (listPool.Count == 0)
{
listPool.Push(new HashSet<int>());
}
return listPool.Pop();
}
private void ReturnHashSetToPool(HashSet<int> hashSet)
{
2022-04-19 19:35:21 +00:00
hashSet.Clear();
2022-04-06 19:53:50 +00:00
listPool.Push(hashSet);
}
}
}