using System; using System.Collections.Generic; using EcsRx.Collections.Entity; using EcsRx.Entities; using EcsRx.Events.Collections; using EcsRx.Extensions; using EcsRx.Groups; using EcsRx.Lookups; using EcsRx.MicroRx.Disposables; using EcsRx.MicroRx.Extensions; using EcsRx.MicroRx.Subjects; namespace EcsRx.Collections.Database { public class EntityDatabase : IEntityDatabase, IDisposable { private readonly CollectionLookup _collections; private readonly IDictionary _collectionSubscriptions; public IReadOnlyList Collections => _collections; public IEntityCollectionFactory EntityCollectionFactory { get; } public IObservable EntityAdded => _onEntityAdded; public IObservable EntityRemoved => _onEntityRemoved; public IObservable EntityComponentsAdded => _onEntityComponentsAdded; public IObservable EntityComponentsRemoving => _onEntityComponentsRemoving; public IObservable EntityComponentsRemoved => _onEntityComponentsRemoved; public IObservable CollectionAdded => _onCollectionAdded; public IObservable CollectionRemoved => _onCollectionRemoved; private readonly Subject _onCollectionAdded; private readonly Subject _onCollectionRemoved; private readonly Subject _onEntityAdded; private readonly Subject _onEntityRemoved; private readonly Subject _onEntityComponentsAdded; private readonly Subject _onEntityComponentsRemoving; private readonly Subject _onEntityComponentsRemoved; public EntityDatabase(IEntityCollectionFactory entityCollectionFactory) { EntityCollectionFactory = entityCollectionFactory; _collections = new CollectionLookup(); _collectionSubscriptions = new Dictionary(); _onCollectionAdded = new Subject(); _onCollectionRemoved = new Subject(); _onEntityAdded = new Subject(); _onEntityRemoved = new Subject(); _onEntityComponentsAdded = new Subject(); _onEntityComponentsRemoving = new Subject(); _onEntityComponentsRemoved = new Subject(); } public void SubscribeToCollection(IEntityCollection collection) { var collectionDisposable = new CompositeDisposable(); collection.EntityAdded.Subscribe(x => _onEntityAdded.OnNext(x)).AddTo(collectionDisposable); collection.EntityRemoved.Subscribe(x => _onEntityRemoved.OnNext(x)).AddTo(collectionDisposable); collection.EntityComponentsAdded.Subscribe(x => _onEntityComponentsAdded.OnNext(x)).AddTo(collectionDisposable); collection.EntityComponentsRemoving.Subscribe(x => _onEntityComponentsRemoving.OnNext(x)).AddTo(collectionDisposable); collection.EntityComponentsRemoved.Subscribe(x => _onEntityComponentsRemoved.OnNext(x)).AddTo(collectionDisposable); _collectionSubscriptions.Add(collection.Id, collectionDisposable); } public void UnsubscribeFromCollection(int id) { _collectionSubscriptions.RemoveAndDispose(id); } public IEntityCollection CreateCollection(int id) { var collection = EntityCollectionFactory.Create(id); AddCollection(collection); return collection; } public void AddCollection(IEntityCollection collection) { _collections.Add(collection); SubscribeToCollection(collection); _onCollectionAdded.OnNext(collection); } public IEntityCollection GetCollection(int id = EntityCollectionLookups.DefaultCollectionId) { if(id == EntityCollectionLookups.DefaultCollectionId && _collections.Count == 0) { CreateCollection(EntityCollectionLookups.DefaultCollectionId); } return _collections[id]; } public void RemoveCollection(int id, bool disposeEntities = true) { if(!_collections.Contains(id)) { return; } var collection = _collections[id]; _collections.Remove(id); UnsubscribeFromCollection(id); _onCollectionRemoved.OnNext(collection); } public bool IsCollection(int id) { return _collections.Contains(id); } public IEnumerable GetEntitiesFor(IGroup group, int collectionId = EntityCollectionLookups.NoCollectionDefined) { if(group is EmptyGroup) { return new IEntity[0]; } if (collectionId != EntityCollectionLookups.NoCollectionDefined) { return _collections[collectionId].MatchingGroup(group); } return Collections.GetAllEntities().MatchingGroup(group); } public IEnumerable GetEntitiesFor(IGroup group, params int[] collectionIds) { if(group is EmptyGroup) { return new IEntity[0]; } if (collectionIds == null || collectionIds.Length == 0) { return Collections.GetAllEntities().MatchingGroup(group); } var matchingEntities = new List(); foreach (var collectionName in collectionIds) { var results = _collections[collectionName].MatchingGroup(group); matchingEntities.AddRange(results); } return matchingEntities; } public IEnumerable GetEntitiesFor(LookupGroup lookupGroup, params int[] collectionIds) { if(lookupGroup.RequiredComponents.Length == 0 && lookupGroup.ExcludedComponents.Length == 0) { return new IEntity[0]; } if (collectionIds == null || collectionIds.Length == 0) { return Collections.GetAllEntities().MatchingGroup(lookupGroup); } var matchingEntities = new List(); foreach (var collectionName in collectionIds) { var results = _collections[collectionName].MatchingGroup(lookupGroup); matchingEntities.AddRange(results); } return matchingEntities; } public void Dispose() { _onEntityAdded.Dispose(); _onEntityRemoved.Dispose(); _onEntityComponentsAdded.Dispose(); _onEntityComponentsRemoving.Dispose(); _onEntityComponentsRemoved.Dispose(); _collectionSubscriptions.RemoveAndDisposeAll(); } } }