using System; using System.Collections.Generic; using System.Runtime.CompilerServices; namespace MoonTools.ECS { internal class RelationDepot { private TypeIndices RelationTypeIndices; private RelationStorage[] storages = new RelationStorage[256]; public RelationDepot(TypeIndices relationTypeIndices) { RelationTypeIndices = relationTypeIndices; } private void Register(int index) where TRelationKind : unmanaged { if (index >= storages.Length) { Array.Resize(ref storages, storages.Length * 2); } storages[index] = new RelationStorage(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private RelationStorage Lookup() where TRelationKind : unmanaged { var storageIndex = RelationTypeIndices.GetIndex(); // TODO: is there some way to avoid this null check? if (storages[storageIndex] == null) { Register(storageIndex); } return (RelationStorage) storages[storageIndex]; } public void Set(Relation relation, TRelationKind relationData) where TRelationKind : unmanaged { Lookup().Set(relation, relationData); } public (bool, bool) Remove(Relation relation) where TRelationKind : unmanaged { return Lookup().Remove(relation); } public void UnrelateAll(int entityID) where TRelationKind : unmanaged { Lookup().UnrelateAll(entityID); } public IEnumerable<(Entity, Entity, TRelationKind)> Relations() where TRelationKind : unmanaged { return Lookup().All(); } public bool Related(int idA, int idB) where TRelationKind : unmanaged { return Lookup().Has(new Relation(idA, idB)); } public IEnumerable<(Entity, TRelationKind)> OutRelations(int entityID) where TRelationKind : unmanaged { return Lookup().OutRelations(entityID); } public (Entity, TRelationKind) OutRelationSingleton(int entityID) where TRelationKind : unmanaged { return Lookup().OutFirst(entityID); } public int OutRelationCount(int entityID) where TRelationKind : unmanaged { return Lookup().OutRelationCount(entityID); } public bool HasOutRelation(int entityID) where TRelationKind : unmanaged { return Lookup().HasOutRelation(entityID); } public IEnumerable<(Entity, TRelationKind)> InRelations(int entityID) where TRelationKind : unmanaged { return Lookup().InRelations(entityID); } public (Entity, TRelationKind) InRelationSingleton(int entityID) where TRelationKind : unmanaged { return Lookup().InFirst(entityID); } public bool HasInRelation(int entityID) where TRelationKind : unmanaged { return Lookup().HasInRelation(entityID); } public int InRelationCount(int entityID) where TRelationKind : unmanaged { return Lookup().InRelationCount(entityID); } // untyped methods used for destroying and snapshots 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, int)> OutRelationIndices(int entityID, int relationTypeIndex) { return storages[relationTypeIndex].OutRelationIndices(entityID); } public void Clear() { for (var i = 0; i < RelationTypeIndices.Count; i += 1) { if (storages[i] != null) { storages[i].Clear(); } } } public void CreateMissingStorages(RelationDepot other) { for (var i = 0; i < RelationTypeIndices.Count; i += 1) { if (storages[i] == null && other.storages[i] != null) { storages[i] = other.storages[i].CreateStorage(); } } } } }