using System.Collections.Generic; using MoonTools.ECS.Collections; namespace MoonTools.ECS { internal class EntityStorage { private int nextID = 0; // FIXME: why is this duplicated? private readonly Stack availableIDs = new Stack(); // FIXME: this is only needed in debug mode private readonly HashSet availableIDHash = new HashSet(); private Dictionary> EntityToComponentTypeIndices = new Dictionary>(); private Dictionary> EntityToRelationTypeIndices = new Dictionary>(); public int Count => nextID - availableIDs.Count; public Dictionary Tags = new Dictionary(); public Entity Create(string tag) { var entity = new Entity(NextID()); if (!EntityToComponentTypeIndices.ContainsKey(entity.ID)) { EntityToComponentTypeIndices.Add(entity.ID, new IndexableSet()); } if (!EntityToRelationTypeIndices.ContainsKey(entity.ID)) { EntityToRelationTypeIndices.Add(entity.ID, new IndexableSet()); } Tags[entity.ID] = tag; return entity; } public bool Exists(in Entity entity) { return Taken(entity.ID); } public void Tag(in Entity entity, string tag) { Tags[entity.ID] = tag; } public void Destroy(in Entity entity) { EntityToComponentTypeIndices[entity.ID].Clear(); EntityToRelationTypeIndices[entity.ID].Clear(); Tags.Remove(entity.ID); Release(entity.ID); } // Returns true if the component is new. public bool SetComponent(int entityID, int componentTypeIndex) { return EntityToComponentTypeIndices[entityID].Add(componentTypeIndex); } public bool HasComponent(int entityID, int componentTypeIndex) { return EntityToComponentTypeIndices[entityID].Contains(componentTypeIndex); } // Returns true if the component existed. public bool RemoveComponent(int entityID, int componentTypeIndex) { return EntityToComponentTypeIndices[entityID].Remove(componentTypeIndex); } public void AddRelationKind(int entityID, int relationIndex) { EntityToRelationTypeIndices[entityID].Add(relationIndex); } public void RemoveRelation(int entityId, int relationIndex) { EntityToRelationTypeIndices[entityId].Remove(relationIndex); } public string Tag(int entityID) { return Tags[entityID]; } public IndexableSet ComponentTypeIndices(int entityID) { return EntityToComponentTypeIndices[entityID]; } public IndexableSet RelationTypeIndices(int entityID) { return EntityToRelationTypeIndices[entityID]; } public void Clear() { nextID = 0; foreach (var componentSet in EntityToComponentTypeIndices.Values) { componentSet.Clear(); } foreach (var relationSet in EntityToRelationTypeIndices.Values) { relationSet.Clear(); } availableIDs.Clear(); availableIDHash.Clear(); } private int NextID() { if (availableIDs.Count > 0) { var id = availableIDs.Pop(); availableIDHash.Remove(id); return id; } else { var id = nextID; nextID += 1; return id; } } private bool Taken(int id) { return !availableIDHash.Contains(id) && id < nextID; } private void Release(int id) { availableIDs.Push(id); availableIDHash.Add(id); } } }