using System; namespace MoonTools.ECS { public class World { internal readonly TypeIndices ComponentTypeIndices = new TypeIndices(); internal readonly TypeIndices RelationTypeIndices = new TypeIndices(); internal readonly EntityStorage EntityStorage = new EntityStorage(); internal readonly ComponentDepot ComponentDepot; internal readonly MessageDepot MessageDepot = new MessageDepot(); internal readonly RelationDepot RelationDepot; internal readonly FilterStorage FilterStorage; public FilterBuilder FilterBuilder => new FilterBuilder(FilterStorage, ComponentTypeIndices); internal readonly ComponentDepot TemplateComponentDepot; public World() { ComponentDepot = new ComponentDepot(ComponentTypeIndices); RelationDepot = new RelationDepot(RelationTypeIndices); FilterStorage = new FilterStorage(EntityStorage, ComponentTypeIndices); TemplateComponentDepot = new ComponentDepot(ComponentTypeIndices); } public Entity CreateEntity() { return EntityStorage.Create(); } public void Set(Entity entity, in TComponent component) where TComponent : unmanaged { #if DEBUG // check for use after destroy if (!EntityStorage.Exists(entity)) { throw new InvalidOperationException("This entity is not valid!"); } #endif ComponentDepot.Set(entity.ID, component); if (EntityStorage.SetComponent(entity.ID, ComponentTypeIndices.GetIndex())) { FilterStorage.Check(entity.ID); } } public void Remove(in Entity entity) where TComponent : unmanaged { if (EntityStorage.RemoveComponent(entity.ID, ComponentTypeIndices.GetIndex())) { // Run filter storage update first so that the entity state is still valid in the remove callback. FilterStorage.Check(entity.ID); ComponentDepot.Remove(entity.ID); } } public void Relate(in Entity entityA, in Entity entityB, TRelationKind relationData) where TRelationKind : unmanaged { RelationDepot.Set(entityA, entityB, relationData); var relationTypeIndex = RelationTypeIndices.GetIndex(); EntityStorage.AddRelationKind(entityA.ID, relationTypeIndex); EntityStorage.AddRelationKind(entityB.ID, relationTypeIndex); } public void Unrelate(in Entity entityA, in Entity entityB) where TRelationKind : unmanaged { var (aEmpty, bEmpty) = RelationDepot.Remove(entityA, entityB); if (aEmpty) { EntityStorage.RemoveRelation(entityA.ID, RelationTypeIndices.GetIndex()); } if (bEmpty) { EntityStorage.RemoveRelation(entityB.ID, RelationTypeIndices.GetIndex()); } } public void UnrelateAll(in Entity entity) where TRelationKind : unmanaged { RelationDepot.UnrelateAll(entity.ID); EntityStorage.RemoveRelation(entity.ID, RelationTypeIndices.GetIndex()); } public void Send(in TMessage message) where TMessage : unmanaged { MessageDepot.Add(message); } public void Send(in Entity entity, in TMessage message) where TMessage : unmanaged { MessageDepot.Add(entity.ID, message); } public void Destroy(in Entity entity) { foreach (var componentTypeIndex in EntityStorage.ComponentTypeIndices(entity.ID)) { // Run filter storage update first so that the entity state is still valid in the remove callback. FilterStorage.RemoveEntity(entity.ID, componentTypeIndex); ComponentDepot.Remove(entity.ID, componentTypeIndex); } foreach (var relationTypeIndex in EntityStorage.RelationTypeIndices(entity.ID)) { RelationDepot.UnrelateAll(entity.ID, relationTypeIndex); EntityStorage.RemoveRelation(entity.ID, relationTypeIndex); } EntityStorage.Destroy(entity); } public void FinishUpdate() { MessageDepot.Clear(); } public Snapshot CreateSnapshot() { return new Snapshot(this); } } }