Пример #1
0
        public IObservableGroup GetObservableGroup(IGroup group, params int[] collectionIds)
        {
            var requiredComponents = ComponentTypeLookup.GetComponentTypes(group.RequiredComponents);
            var excludedComponents = ComponentTypeLookup.GetComponentTypes(group.ExcludedComponents);
            var lookupGroup        = new LookupGroup(requiredComponents, excludedComponents);

            var observableGroupToken = new ObservableGroupToken(lookupGroup, collectionIds);

            if (_observableGroups.Contains(observableGroupToken))
            {
                return(_observableGroups[observableGroupToken]);
            }

            var entityMatches = GetEntitiesFor(lookupGroup, collectionIds);
            var configuration = new ObservableGroupConfiguration
            {
                ObservableGroupToken = observableGroupToken,
                InitialEntities      = entityMatches
            };

            if (collectionIds != null && collectionIds.Length > 0)
            {
                configuration.NotifyingCollections = _collections.Where(x => collectionIds.Contains(x.Id));
            }
            else
            {
                configuration.NotifyingCollections = new [] { this };
            }

            var observableGroup = ObservableGroupFactory.Create(configuration);

            _observableGroups.Add(observableGroup);

            return(_observableGroups[observableGroupToken]);
        }
Пример #2
0
        public IObservableGroup GetObservableGroup(IGroup group, string collectionName = null)
        {
            var requiredComponents   = ComponentTypeLookup.GetComponentTypes(group.RequiredComponents);
            var excludedComponents   = ComponentTypeLookup.GetComponentTypes(group.ExcludedComponents);
            var lookupGroup          = new LookupGroup(requiredComponents, excludedComponents);
            var observableGroupToken = new ObservableGroupToken(lookupGroup, collectionName);

            if (_observableGroups.ContainsKey(observableGroupToken))
            {
                return(_observableGroups[observableGroupToken]);
            }

            var entityMatches = GetEntitiesFor(lookupGroup, collectionName);
            var configuration = new ObservableGroupConfiguration
            {
                ObservableGroupToken = observableGroupToken,
                InitialEntities      = entityMatches
            };

            if (collectionName != null)
            {
                configuration.NotifyingCollection = _collections[collectionName];
            }
            else
            {
                configuration.NotifyingCollection = this;
            }

            var observableGroup = ObservableGroupFactory.Create(configuration);

            _observableGroups.Add(observableGroupToken, observableGroup);

            return(_observableGroups[observableGroupToken]);
        }
Пример #3
0
        public void should_add_entity_and_raise_event_when_components_match_group()
        {
            var collectionName = "default";
            var accessorToken  = new ObservableGroupToken(new[] { 1 }, new [] { 2 }, collectionName);
            var mockCollection = Substitute.For <IEntityCollection>();

            mockCollection.Name.Returns(collectionName);

            var applicableEntity = Substitute.For <IEntity>();

            applicableEntity.Id.Returns(1);

            var mockCollectionNotifier = Substitute.For <INotifyingEntityCollection>();

            var componentRemoved = new Subject <ComponentsChangedEvent>();

            mockCollectionNotifier.EntityAdded.Returns(Observable.Empty <CollectionEntityEvent>());
            mockCollectionNotifier.EntityRemoved.Returns(Observable.Empty <CollectionEntityEvent>());
            mockCollectionNotifier.EntityComponentsAdded.Returns(Observable.Empty <ComponentsChangedEvent>());
            mockCollectionNotifier.EntityComponentsRemoving.Returns(Observable.Empty <ComponentsChangedEvent>());
            mockCollectionNotifier.EntityComponentsRemoved.Returns(componentRemoved);

            var observableGroup = new ObservableGroup(accessorToken, new IEntity[0], mockCollectionNotifier);
            var wasCalled       = 0;

            observableGroup.OnEntityAdded.Subscribe(x => wasCalled++);

            applicableEntity.HasAllComponents(accessorToken.LookupGroup.RequiredComponents).Returns(true);
            applicableEntity.HasAnyComponents(accessorToken.LookupGroup.ExcludedComponents).Returns(false);
            componentRemoved.OnNext(new ComponentsChangedEvent(mockCollection, applicableEntity, null));

            Assert.Contains(applicableEntity, observableGroup.CachedEntities.Values);
            Assert.Equal(1, wasCalled);
        }
Пример #4
0
        public void should_not_cache_applicable_entity_when_added_to_different_collection()
        {
            var mockEventSystem = Substitute.For <IEventSystem>();
            var collectionName  = "defaut";
            var accessorToken   = new ObservableGroupToken(new[] { typeof(TestComponentOne), typeof(TestComponentTwo) }, "some-other-entityCollection-name");
            var mockCollection  = Substitute.For <IEntityCollection>();

            mockCollection.Name.Returns(collectionName);

            var applicableEntity = new Entity(Guid.NewGuid(), mockEventSystem);

            applicableEntity.AddComponent <TestComponentOne>();
            applicableEntity.AddComponent <TestComponentTwo>();

            var unapplicableEntity = new Entity(Guid.NewGuid(), mockEventSystem);

            unapplicableEntity.AddComponent <TestComponentOne>();

            var underlyingEvent = new ReactiveProperty <EntityAddedEvent>(new EntityAddedEvent(applicableEntity, mockCollection));

            mockEventSystem.Receive <EntityAddedEvent>().Returns(underlyingEvent);
            mockEventSystem.Receive <EntityRemovedEvent>().Returns(Observable.Empty <EntityRemovedEvent>());
            mockEventSystem.Receive <ComponentsAddedEvent>().Returns(Observable.Empty <ComponentsAddedEvent>());
            mockEventSystem.Receive <ComponentsRemovedEvent>().Returns(Observable.Empty <ComponentsRemovedEvent>());

            var cacheableGroupAccessor = new ObservableGroup(mockEventSystem, accessorToken, new IEntity[] { });

            underlyingEvent.SetValueAndForceNotify(new EntityAddedEvent(unapplicableEntity, mockCollection));

            Assert.Empty(cacheableGroupAccessor.CachedEntities);
        }
Пример #5
0
        public void should_correctly_notify_when_matching_component_removed()
        {
            var componentTypes  = new[] { typeof(TestComponentOne), typeof(TestComponentTwo) };
            var fakeEventSystem = new EventSystem(new MessageBroker());
            var accessorToken   = new ObservableGroupToken(componentTypes, "default");

            var fakeEntity1 = new Entity(Guid.Empty, fakeEventSystem);

            fakeEntity1.AddComponent <TestComponentOne>();
            fakeEntity1.AddComponent <TestComponentTwo>();
            fakeEntity1.AddComponent <TestComponentThree>();

            var fakeEntity2 = new Entity(Guid.Empty, fakeEventSystem);

            fakeEntity2.AddComponent <TestComponentOne>();
            fakeEntity2.AddComponent <TestComponentThree>();

            var timesCalled = 0;

            var observableGroup = new ObservableGroup(fakeEventSystem, accessorToken, new IEntity[] { fakeEntity1 });

            ObservableExtensions.Subscribe <IEntity>(observableGroup.OnEntityRemoved, x =>
            {
                Assert.Equal <IEntity>(fakeEntity1, x);
                timesCalled++;
            });

            fakeEntity1.RemoveComponent <TestComponentThree>();
            fakeEntity1.RemoveComponent <TestComponentTwo>();
            fakeEntity2.RemoveComponent <TestComponentThree>();

            Assert.Equal(1, timesCalled);
        }
Пример #6
0
        public void should_only_add_entity_when_components_match_group()
        {
            var mockEventSystem = Substitute.For <IEventSystem>();
            var accessorToken   = new ObservableGroupToken(new[] { typeof(TestComponentOne), typeof(TestComponentTwo) }, "default");

            var existingEntityOne = new Entity(Guid.NewGuid(), mockEventSystem);
            var componentToAdd    = new TestComponentOne();

            existingEntityOne.AddComponent <TestComponentTwo>();

            var existingEntityTwo     = new Entity(Guid.NewGuid(), mockEventSystem);
            var unapplicableComponent = new TestComponentThree();

            existingEntityTwo.AddComponent <TestComponentOne>();

            var dummyEventToSeedMock = new ComponentsAddedEvent(new Entity(Guid.NewGuid(), mockEventSystem), new[] { new TestComponentOne() });
            var underlyingEvent      = new ReactiveProperty <ComponentsAddedEvent>(dummyEventToSeedMock);

            mockEventSystem.Receive <ComponentsAddedEvent>().Returns(underlyingEvent);
            mockEventSystem.Receive <ComponentsRemovedEvent>().Returns(Observable.Empty <ComponentsRemovedEvent>());
            mockEventSystem.Receive <EntityAddedEvent>().Returns(Observable.Empty <EntityAddedEvent>());
            mockEventSystem.Receive <EntityRemovedEvent>().Returns(Observable.Empty <EntityRemovedEvent>());

            var cacheableGroupAccessor = new ObservableGroup(mockEventSystem, accessorToken, new IEntity[] {});

            existingEntityOne.AddComponent(componentToAdd);
            underlyingEvent.SetValueAndForceNotify(new ComponentsAddedEvent(existingEntityOne, new[] { componentToAdd }));

            existingEntityTwo.AddComponent(unapplicableComponent);
            underlyingEvent.SetValueAndForceNotify(new ComponentsAddedEvent(existingEntityTwo, new[] { unapplicableComponent }));

            Assert.Equal(1, cacheableGroupAccessor.CachedEntities.Count);
            Assert.Equal <IEntity>(existingEntityOne, cacheableGroupAccessor.CachedEntities[existingEntityOne.Id]);
        }
Пример #7
0
        public void should_include_entity_snapshot_on_creation()
        {
            var mockEventSystem = Substitute.For <IEventSystem>();
            var accessorToken   = new ObservableGroupToken(new Type[] { }, "default");

            mockEventSystem.Receive <EntityAddedEvent>().Returns(Observable.Empty <EntityAddedEvent>());
            mockEventSystem.Receive <EntityRemovedEvent>().Returns(Observable.Empty <EntityRemovedEvent>());
            mockEventSystem.Receive <ComponentsAddedEvent>().Returns(Observable.Empty <ComponentsAddedEvent>());
            mockEventSystem.Receive <ComponentsRemovedEvent>().Returns(Observable.Empty <ComponentsRemovedEvent>());

            var dummyEntitySnapshot = new List <IEntity>
            {
                new Entity(Guid.NewGuid(), mockEventSystem),
                new Entity(Guid.NewGuid(), mockEventSystem),
                new Entity(Guid.NewGuid(), mockEventSystem)
            };

            var cacheableGroupAccessor = new ObservableGroup(mockEventSystem, accessorToken, dummyEntitySnapshot);

            Assert.Equal(3, cacheableGroupAccessor.CachedEntities.Count);
            Assert.Equal(dummyEntitySnapshot[0], cacheableGroupAccessor.CachedEntities[dummyEntitySnapshot[0].Id]);
            Assert.Equal(dummyEntitySnapshot[1], cacheableGroupAccessor.CachedEntities[dummyEntitySnapshot[1].Id]);
            Assert.Equal(dummyEntitySnapshot[2], cacheableGroupAccessor.CachedEntities[dummyEntitySnapshot[2].Id]);

            cacheableGroupAccessor.Dispose();
        }
Пример #8
0
        public void should_only_remove_applicable_entity_when_entity_removed()
        {
            var mockEventSystem = Substitute.For <IEventSystem>();
            var accessorToken   = new ObservableGroupToken(new[] { typeof(TestComponentOne), typeof(TestComponentTwo) }, "default");
            var mockCollection  = Substitute.For <IEntityCollection>();

            var existingEntityOne = new Entity(Guid.NewGuid(), mockEventSystem);

            existingEntityOne.AddComponent <TestComponentOne>();
            existingEntityOne.AddComponent <TestComponentTwo>();

            var existingEntityTwo = new Entity(Guid.NewGuid(), mockEventSystem);

            existingEntityTwo.AddComponent <TestComponentOne>();
            existingEntityTwo.AddComponent <TestComponentTwo>();

            var unapplicableEntity = new Entity(Guid.NewGuid(), mockEventSystem);

            unapplicableEntity.AddComponent <TestComponentOne>();

            var underlyingEvent = new ReactiveProperty <EntityRemovedEvent>(new EntityRemovedEvent(unapplicableEntity, mockCollection));

            mockEventSystem.Receive <EntityRemovedEvent>().Returns(underlyingEvent);
            mockEventSystem.Receive <EntityAddedEvent>().Returns(Observable.Empty <EntityAddedEvent>());
            mockEventSystem.Receive <ComponentsAddedEvent>().Returns(Observable.Empty <ComponentsAddedEvent>());
            mockEventSystem.Receive <ComponentsRemovedEvent>().Returns(Observable.Empty <ComponentsRemovedEvent>());

            var cacheableGroupAccessor = new ObservableGroup(mockEventSystem, accessorToken, new IEntity[] { existingEntityOne, existingEntityTwo });

            underlyingEvent.SetValueAndForceNotify(new EntityRemovedEvent(existingEntityOne, mockCollection));

            Assert.Equal(1, cacheableGroupAccessor.CachedEntities.Count);
            Assert.Equal <IEntity>(existingEntityTwo, cacheableGroupAccessor.CachedEntities[existingEntityTwo.Id]);
        }
Пример #9
0
        public void should_remove_entity_and_raise_events_when_entity_removed_with_components()
        {
            var collectionName = "default";
            var accessorToken  = new ObservableGroupToken(new[] { 1, 2 }, new int[0], collectionName);
            var mockCollection = Substitute.For <IEntityCollection>();

            mockCollection.Name.Returns(collectionName);

            var applicableEntity = Substitute.For <IEntity>();

            applicableEntity.Id.Returns(1);
            applicableEntity.HasComponent(Arg.Is <int>(x => accessorToken.LookupGroup.RequiredComponents.Contains(x))).Returns(true);
            applicableEntity.HasComponent(Arg.Is <int>(x => accessorToken.LookupGroup.ExcludedComponents.Contains(x))).Returns(false);

            var mockCollectionNotifier = Substitute.For <INotifyingEntityCollection>();

            var entityRemoved     = new Subject <CollectionEntityEvent>();
            var componentRemoving = new Subject <ComponentsChangedEvent>();

            mockCollectionNotifier.EntityRemoved.Returns(entityRemoved);
            mockCollectionNotifier.EntityAdded.Returns(Observable.Empty <CollectionEntityEvent>());
            mockCollectionNotifier.EntityComponentsAdded.Returns(Observable.Empty <ComponentsChangedEvent>());
            mockCollectionNotifier.EntityComponentsRemoving.Returns(componentRemoving);
            mockCollectionNotifier.EntityComponentsRemoved.Returns(Observable.Empty <ComponentsChangedEvent>());

            var observableGroup   = new ObservableGroup(accessorToken, new[] { applicableEntity }, mockCollectionNotifier);
            var wasRemovingCalled = 0;

            observableGroup.OnEntityRemoving.Subscribe(x => wasRemovingCalled++);
            var wasRemovedCalled = 0;

            observableGroup.OnEntityRemoved.Subscribe(x => wasRemovedCalled++);

            componentRemoving.OnNext(new ComponentsChangedEvent(null, applicableEntity, new[] { 1 }));

            Assert.Contains(applicableEntity, observableGroup.CachedEntities.Values);
            Assert.Equal(1, wasRemovingCalled);
            Assert.Equal(0, wasRemovedCalled);

            wasRemovingCalled = wasRemovedCalled = 0;
            entityRemoved.OnNext(new CollectionEntityEvent(applicableEntity, null));

            Assert.DoesNotContain(applicableEntity, observableGroup.CachedEntities.Values);
            Assert.Equal(0, wasRemovingCalled);
            Assert.Equal(1, wasRemovedCalled);
        }
Пример #10
0
        public void should_add_entity_and_raise_event_when_applicable_entity_added()
        {
            var collectionName = "default";
            var accessorToken  = new ObservableGroupToken(new[] { 1, 2 }, new int[0], collectionName);
            var mockCollection = Substitute.For <IEntityCollection>();

            mockCollection.Name.Returns(collectionName);

            var applicableEntity = Substitute.For <IEntity>();

            applicableEntity.Id.Returns(1);
            applicableEntity.HasComponent(Arg.Is <int>(x => accessorToken.LookupGroup.RequiredComponents.Contains(x))).Returns(true);

            var unapplicableEntity = Substitute.For <IEntity>();

            unapplicableEntity.Id.Returns(2);
            unapplicableEntity.HasComponent(Arg.Is <int>(x => accessorToken.LookupGroup.RequiredComponents.Contains(x))).Returns(false);

            var mockCollectionNotifier = Substitute.For <INotifyingEntityCollection>();

            var entityAddedSub = new Subject <CollectionEntityEvent>();

            mockCollectionNotifier.EntityAdded.Returns(entityAddedSub);
            mockCollectionNotifier.EntityRemoved.Returns(Observable.Empty <CollectionEntityEvent>());
            mockCollectionNotifier.EntityComponentsAdded.Returns(Observable.Empty <ComponentsChangedEvent>());
            mockCollectionNotifier.EntityComponentsRemoving.Returns(Observable.Empty <ComponentsChangedEvent>());
            mockCollectionNotifier.EntityComponentsRemoved.Returns(Observable.Empty <ComponentsChangedEvent>());

            var observableGroup = new ObservableGroup(accessorToken, new IEntity[0], mockCollectionNotifier);
            var wasCalled       = 0;

            observableGroup.OnEntityAdded.Subscribe(x => wasCalled++);

            entityAddedSub.OnNext(new CollectionEntityEvent(unapplicableEntity, mockCollection));
            Assert.Empty(observableGroup.CachedEntities);

            entityAddedSub.OnNext(new CollectionEntityEvent(applicableEntity, mockCollection));
            Assert.Equal(1, observableGroup.CachedEntities.Count);
            Assert.Equal(applicableEntity, observableGroup.CachedEntities[applicableEntity.Id]);

            Assert.Equal(1, wasCalled);
        }
Пример #11
0
        public IObservableGroup CreateObservableGroup(IGroup group, string collectionName = null)
        {
            var groupAccessorToken = new ObservableGroupToken(group.MatchesComponents.ToArray(), collectionName);

            if (_groupAccessors.ContainsKey(groupAccessorToken))
            {
                return(_groupAccessors[groupAccessorToken]);
            }

            var entityMatches = GetEntitiesFor(group, collectionName);
            var groupAccessor = ObservableGroupFactory.Create(new ObservableGroupConfiguration
            {
                ObservableGroupToken = groupAccessorToken,
                InitialEntities      = entityMatches
            });

            _groupAccessors.Add(groupAccessorToken, groupAccessor);

            return(_groupAccessors[groupAccessorToken]);
        }
Пример #12
0
        public void should_correctly_notify_when_matching_entity_removed()
        {
            var componentTypes  = new[] { typeof(TestComponentOne), typeof(TestComponentTwo) };
            var mockEventSystem = Substitute.For <IEventSystem>();
            var mockCollection  = Substitute.For <IEntityCollection>();
            var accessorToken   = new ObservableGroupToken(componentTypes, "default");

            var fakeEntity1 = new Entity(Guid.Empty, mockEventSystem);

            fakeEntity1.AddComponent <TestComponentOne>();
            fakeEntity1.AddComponent <TestComponentTwo>();

            var fakeEntity2 = new Entity(Guid.Empty, mockEventSystem);

            fakeEntity2.AddComponent <TestComponentOne>();
            fakeEntity2.AddComponent <TestComponentThree>();

            var timesCalled = 0;

            mockCollection.Name.Returns("default");

            var underlyingEvent = new Subject <EntityRemovedEvent>();

            mockEventSystem.Receive <ComponentsAddedEvent>().Returns(Observable.Empty <ComponentsAddedEvent>());
            mockEventSystem.Receive <ComponentsRemovedEvent>().Returns(Observable.Empty <ComponentsRemovedEvent>());
            mockEventSystem.Receive <EntityAddedEvent>().Returns(Observable.Empty <EntityAddedEvent>());
            mockEventSystem.Receive <EntityRemovedEvent>().Returns(underlyingEvent);

            var observableGroup = new ObservableGroup(mockEventSystem, accessorToken, new IEntity[] { fakeEntity1 });

            ObservableExtensions.Subscribe <IEntity>(observableGroup.OnEntityRemoved, x =>
            {
                Assert.Equal <IEntity>(fakeEntity1, x);
                timesCalled++;
            });

            underlyingEvent.OnNext(new EntityRemovedEvent(fakeEntity1, mockCollection));
            underlyingEvent.OnNext(new EntityRemovedEvent(fakeEntity2, mockCollection));

            Assert.Equal(1, timesCalled);
        }
Пример #13
0
        public void should_include_entity_snapshot_on_creation()
        {
            var mockCollectionNotifier = Substitute.For <INotifyingEntityCollection>();
            var accessorToken          = new ObservableGroupToken(new[] { 1 }, new int[0], "default");

            var applicableEntity1    = Substitute.For <IEntity>();
            var applicableEntity2    = Substitute.For <IEntity>();
            var notApplicableEntity1 = Substitute.For <IEntity>();

            applicableEntity1.Id.Returns(1);
            applicableEntity2.Id.Returns(2);
            notApplicableEntity1.Id.Returns(3);

            applicableEntity1.HasComponent(Arg.Any <int>()).Returns(true);
            applicableEntity2.HasComponent(Arg.Any <int>()).Returns(true);
            notApplicableEntity1.HasComponent(Arg.Any <int>()).Returns(false);

            var dummyEntitySnapshot = new List <IEntity>
            {
                applicableEntity1,
                applicableEntity2,
                notApplicableEntity1
            };

            mockCollectionNotifier.EntityAdded.Returns(Observable.Empty <CollectionEntityEvent>());
            mockCollectionNotifier.EntityRemoved.Returns(Observable.Empty <CollectionEntityEvent>());
            mockCollectionNotifier.EntityComponentsAdded.Returns(Observable.Empty <ComponentsChangedEvent>());
            mockCollectionNotifier.EntityComponentsRemoving.Returns(Observable.Empty <ComponentsChangedEvent>());
            mockCollectionNotifier.EntityComponentsRemoved.Returns(Observable.Empty <ComponentsChangedEvent>());

            var observableGroup = new ObservableGroup(accessorToken, dummyEntitySnapshot, mockCollectionNotifier);

            Assert.Equal(2, observableGroup.CachedEntities.Count);
            Assert.Contains(applicableEntity1, observableGroup.CachedEntities.Values);
            Assert.Contains(applicableEntity2, observableGroup.CachedEntities.Values);
        }
        public void should_correctly_differentiate_tokens()
        {
            var defaultRequired = new[] { 1 };
            var defaultExcluded = new int[0];
            var token1          = new ObservableGroupToken(defaultRequired, defaultExcluded);
            var token2          = new ObservableGroupToken(defaultRequired, defaultExcluded, 1);
            var token3          = new ObservableGroupToken(defaultRequired, defaultExcluded, 1, 2);

            Assert.NotEqual(token1, token2);
            Assert.NotEqual(token1, token3);
            Assert.NotEqual(token2, token3);

            Assert.NotEqual(token1.GetHashCode(), token2.GetHashCode());
            Assert.NotEqual(token1.GetHashCode(), token3.GetHashCode());
            Assert.NotEqual(token2.GetHashCode(), token3.GetHashCode());

            Assert.Equal(token1, token1);
            Assert.Equal(token2, token2);
            Assert.Equal(token3, token3);

            Assert.Equal(token1.GetHashCode(), token1.GetHashCode());
            Assert.Equal(token2.GetHashCode(), token2.GetHashCode());
            Assert.Equal(token3.GetHashCode(), token3.GetHashCode());
        }