예제 #1
0
        public void TestReset()
        {
            var registry      = new ServiceRegistry();
            var entityManager = new CustomEntityManager(registry);

            // Entity with a sub-Entity
            var childEntity0 = new Entity();
            var entity       = new Entity();

            entity.AddChild(childEntity0);

            // ================================================================
            // 1) Add entity with sub-entity and check EntityManager and TransformProcessor
            // ================================================================
            entityManager.Add(entity);
            var transformProcessor = entityManager.GetProcessor <TransformProcessor>();

            Assert.NotNull(transformProcessor);

            Assert.Equal(2, entityManager.Count);
            Assert.Single(transformProcessor.TransformationRoots);
            Assert.Contains(entity.Transform, transformProcessor.TransformationRoots);

            // ================================================================
            // 2) Reset the manager
            // ================================================================
            entityManager.Reset();

            Assert.Empty(entityManager);
            Assert.Empty(entityManager.MapComponentTypeToProcessors);
            Assert.Empty(entityManager.Processors);
            Assert.Empty(transformProcessor.TransformationRoots);
            Assert.Null(transformProcessor.EntityManager);
        }
예제 #2
0
        private CameraComponent AddCamera(bool enabled, SceneCameraSlotId slot)
        {
            var camera = new CameraComponent {
                Enabled = enabled, Slot = slot
            };

            entityManager.Add(new Entity {
                camera
            });
            return(camera);
        }
예제 #3
0
        public void TestEntityAndChildren()
        {
            var registry      = new ServiceRegistry();
            var entityManager = new CustomEntityManager(registry);

            // Entity with a sub-Entity
            var childEntity0 = new Entity();
            var entity       = new Entity();

            entity.AddChild(childEntity0);

            // ================================================================
            // 1) Add entity with sub-entity and check EntityManager and TransformProcessor
            // ================================================================
            entityManager.Add(entity);
            var transformProcessor = entityManager.GetProcessor <TransformProcessor>();

            Assert.NotNull(transformProcessor);

            Assert.Equal(2, entityManager.Count);
            Assert.Single(transformProcessor.TransformationRoots);
            Assert.Contains(entity.Transform, transformProcessor.TransformationRoots);

            // ================================================================
            // 2) Remove child from entity while the Entity is still in the EntityManager
            // ================================================================
            entity.Transform.Children.RemoveAt(0);

            Assert.Single(entityManager);
            Assert.Single(transformProcessor.TransformationRoots);
            Assert.Contains(entity.Transform, transformProcessor.TransformationRoots);

            // ================================================================
            // 3) Add a child to the root entity while the Entity is still in the EntityManager
            // ================================================================
            var childEntity = new Entity();

            entity.AddChild(childEntity);

            Assert.Equal(2, entityManager.Count);
            Assert.Single(transformProcessor.TransformationRoots);
            Assert.Contains(entity.Transform, transformProcessor.TransformationRoots);

            // ================================================================
            // 3) Remove top level entity
            // ================================================================
            entityManager.Remove(entity);

            Assert.Empty(entityManager);
            Assert.Empty(transformProcessor.TransformationRoots);
        }
예제 #4
0
        public void TestHierarchyChanged()
        {
            var registry      = new ServiceRegistry();
            var entityManager = new CustomEntityManager(registry);

            // Entity with a sub-Entity
            var childEntity0 = new Entity();
            var entity       = new Entity();

            entityManager.Add(entity);

            var addChildCheck        = false;
            var removeChildCheck     = false;
            var prevRootAsChildCheck = false;

            Action <Entity>[] currentAction = { null };

            entityManager.HierarchyChanged += (sender, entity1) =>
            {
                currentAction[0]?.Invoke(entity1);
            };

            var addChildAction = new Action <Entity>(otherEntity =>
            {
                if (otherEntity == childEntity0)
                {
                    addChildCheck = true;
                }
            });

            currentAction[0] = addChildAction;
            entity.AddChild(childEntity0);

            var removeChildAction = new Action <Entity>(otherEntity =>
            {
                if (otherEntity == childEntity0)
                {
                    removeChildCheck = true;
                }
            });

            currentAction[0] = removeChildAction;
            entity.RemoveChild(childEntity0);

            entityManager.Add(childEntity0);

            var prevRootAction = new Action <Entity>(otherEntity =>
            {
                if (otherEntity == entity)
                {
                    prevRootAsChildCheck = true;
                }
            });

            currentAction[0] = prevRootAction;
            childEntity0.AddChild(entity);

            Assert.True(addChildCheck);
            Assert.True(removeChildCheck);
            Assert.True(prevRootAsChildCheck);
        }
예제 #5
0
        public void TestProcessorWithRequiredTypes()
        {
            var registry      = new ServiceRegistry();
            var entityManager = new CustomEntityManager(registry);

            var events = new List <CustomEntityComponentEventArgs>();
            var entity = new Entity()
            {
                new CustomEntityComponentWithDependency()
                {
                    Changed = evt => events.Add(evt)
                }
            };
            var customComponent = entity.Get <CustomEntityComponentWithDependency>();

            // ================================================================
            // 1) Add entity, check that processors and required processors are correctly in EntityManager
            // ================================================================

            entityManager.Add(entity);

            // Check internal processors
            Assert.Equal(2, entityManager.MapComponentTypeToProcessors.Count);
            Assert.True(entityManager.MapComponentTypeToProcessors.ContainsKey(typeof(TransformComponent).GetTypeInfo()));
            Assert.True(entityManager.MapComponentTypeToProcessors.ContainsKey(typeof(CustomEntityComponentWithDependency).GetTypeInfo()));

            var customProcessor = entityManager.GetProcessor <CustomEntityComponentProcessorWithDependency>();

            // Because the custom processor has a dependency on TransformComponent, we are checking that the dependencies is correctly registered back in the
            // list of processors for TransformComponent that should have a link to the custom processor
            var processorsForTransform = entityManager.MapComponentTypeToProcessors[typeof(TransformComponent).GetTypeInfo()];

            // there is the HierarchicalProcessor and TransformProcessor
            Assert.Single(processorsForTransform);
            Assert.NotNull(processorsForTransform.Dependencies);
            Assert.Single(processorsForTransform.Dependencies);
            Assert.Equal(customProcessor, processorsForTransform.Dependencies[0]);

            // Check that the custom processor is empty
            var processorsForCustom = entityManager.MapComponentTypeToProcessors[typeof(CustomEntityComponentWithDependency).GetTypeInfo()];

            Assert.Single(processorsForCustom);
            Assert.Null(processorsForCustom.Dependencies);

            // ================================================================
            // 2) Override the TransformComponent with a new TransformComponent and check that required Processor are called and updated
            // ================================================================

            var previousTransform = entity.Transform;
            var newTransform      = new TransformComponent();

            entity.Components[0] = newTransform;

            // If the entity manager is working property, because the TransformComponent is updated, all processor depending on it
            // will be called on the entity
            // We are checking here that the new transform is correctly copied to the custom component by the custom processor.
            Assert.Equal(newTransform, customComponent.Link);

            // ================================================================
            // 3) Remove TransformComponent
            // ================================================================

            entity.Components.RemoveAt(0);

            // The link is not updated, but it is ok, as it is an associated data that is no longer part of the processor
            Assert.Null(customComponent.Link);
            Assert.Empty(customProcessor.CurrentComponentDatas);
        }
예제 #6
0
        public void TestDefaultProcessors()
        {
            var registry      = new ServiceRegistry();
            var entityManager = new CustomEntityManager(registry);

            // Create events collector to check fired events on EntityManager
            var componentTypes = new List <Type>();
            var entityAdded    = new List <Entity>();
            var entityRemoved  = new List <Entity>();

            entityManager.ComponentTypeAdded += (sender, type) => componentTypes.Add(type);
            entityManager.EntityAdded        += (sender, entity1) => entityAdded.Add(entity1);
            entityManager.EntityRemoved      += (sender, entity1) => entityRemoved.Add(entity1);

            // No processors registered by default
            Assert.Empty(entityManager.Processors);

            // ================================================================
            // 1) Add an entity with the default TransformComponent to the Entity Manager
            // ================================================================

            var entity = new Entity();

            entityManager.Add(entity);

            // Check types are correctly registered
            Assert.Single(componentTypes);
            Assert.Equal(typeof(TransformComponent), componentTypes[0]);

            // Check entity correctly added
            Assert.Single(entityManager);
            Assert.True(entityManager.Contains(entity));
            Assert.Single(entityAdded);
            Assert.Equal(entity, entityAdded[0]);
            Assert.Empty(entityRemoved);

            // We should have 1 processor
            Assert.Single(entityManager.Processors);

            var transformProcessor = entityManager.Processors[0] as TransformProcessor;

            Assert.NotNull(transformProcessor);

            Assert.Single(transformProcessor.TransformationRoots);
            // TODO: Check the root entity.Transform

            // Check internal mapping of component types => EntityProcessor
            Assert.Single(entityManager.MapComponentTypeToProcessors);
            Assert.True(entityManager.MapComponentTypeToProcessors.ContainsKey(typeof(TransformComponent).GetTypeInfo()));

            var processorListForTransformComponentType = entityManager.MapComponentTypeToProcessors[typeof(TransformComponent).GetTypeInfo()];

            Assert.Single(processorListForTransformComponentType);
            Assert.True(processorListForTransformComponentType[0] is TransformProcessor);

            // clear events collector
            componentTypes.Clear();
            entityAdded.Clear();
            entityRemoved.Clear();

            // ================================================================
            // 2) Add another empty entity
            // ================================================================

            var newEntity = new Entity();

            entityManager.Add(newEntity);

            // We should not have new component types registered
            Assert.Empty(componentTypes);

            // Check entity correctly added
            Assert.Equal(2, entityManager.Count);
            Assert.True(entityManager.Contains(newEntity));
            Assert.Single(entityAdded);
            Assert.Equal(newEntity, entityAdded[0]);
            Assert.Empty(entityRemoved);

            // We should still have 2 processors
            Assert.Single(entityManager.Processors);
            Assert.Equal(2, transformProcessor.TransformationRoots.Count);

            componentTypes.Clear();
            entityAdded.Clear();
            entityRemoved.Clear();

            // ================================================================
            // 3) Remove previous entity
            // ================================================================

            entityManager.Remove(newEntity);

            // Check entity correctly removed
            Assert.Single(entityManager);
            Assert.False(entityManager.Contains(newEntity));
            Assert.Empty(entityAdded);
            Assert.Single(entityRemoved);
            Assert.Equal(newEntity, entityRemoved[0]);

            Assert.Single(transformProcessor.TransformationRoots);

            componentTypes.Clear();
            entityAdded.Clear();
            entityRemoved.Clear();
        }
예제 #7
0
        public void TestMultipleComponents()
        {
            var registry      = new ServiceRegistry();
            var entityManager = new CustomEntityManager(registry);

            var events = new List <CustomEntityComponentEventArgs>();

            var entity = new Entity
            {
                new CustomEntityComponent()
                {
                    Changed = e => events.Add(e)
                }
            };
            var customComponent = entity.Get <CustomEntityComponent>();

            // ================================================================
            // 1) Add an entity with a component to the Entity Manager
            // ================================================================

            // Add component
            entityManager.Add(entity);

            // Check that component was correctly processed when first adding the entity
            Assert.Single(entityManager);
            Assert.Equal(2, entityManager.Processors.Count);

            // Verify that the processor has correctly registered the component
            var customProcessor = entityManager.GetProcessor <CustomEntityComponentProcessor>();

            Assert.NotNull(customProcessor);

            Assert.Single(customProcessor.CurrentComponentDatas);
            Assert.True(customProcessor.CurrentComponentDatas.ContainsKey(customComponent));

            // Verify that events are correctly propagated
            var expectedEvents = new List <CustomEntityComponentEventArgs>()
            {
                new CustomEntityComponentEventArgs(CustomEntityComponentEventType.GenerateComponentData, entity, customComponent),
                new CustomEntityComponentEventArgs(CustomEntityComponentEventType.EntityComponentAdding, entity, customComponent),
            };

            Assert.Equal(expectedEvents, events);
            events.Clear();

            // ================================================================
            // 2) Add a component to the entity that is already handled by the Entity Manager
            // ================================================================

            // Check that component is correctly processed when adding it after the entity is already into the EntityManager
            var customComponent2 = new CustomEntityComponent()
            {
                Changed = e => events.Add(e)
            };

            entity.Components.Add(customComponent2);

            // Verify that the processor has correctly registered the component
            Assert.Equal(2, customProcessor.CurrentComponentDatas.Count);
            Assert.True(customProcessor.CurrentComponentDatas.ContainsKey(customComponent2));

            expectedEvents = new List <CustomEntityComponentEventArgs>()
            {
                new CustomEntityComponentEventArgs(CustomEntityComponentEventType.GenerateComponentData, entity, customComponent2),
                new CustomEntityComponentEventArgs(CustomEntityComponentEventType.EntityComponentAdding, entity, customComponent2),
            };
            Assert.Equal(expectedEvents, events);
            events.Clear();

            // ================================================================
            // 3) Remove the 1st CustomEntityComponent from the entity
            // ================================================================

            // Test remove first component
            entity.Components.Remove(customComponent);

            // Verify that the processor has correctly removed the component
            Assert.Single(customProcessor.CurrentComponentDatas);
            Assert.False(customProcessor.CurrentComponentDatas.ContainsKey(customComponent));

            Assert.Null(customComponent.Entity);
            expectedEvents = new List <CustomEntityComponentEventArgs>()
            {
                new CustomEntityComponentEventArgs(CustomEntityComponentEventType.EntityComponentRemoved, entity, customComponent),
            };
            Assert.Equal(expectedEvents, events);
            events.Clear();

            // ================================================================
            // 4) Remove the 2nd CustomEntityComponent from the entity
            // ================================================================

            // Test remove second component
            entity.Components.Remove(customComponent2);

            // Verify that the processor has correctly removed the component
            Assert.Empty(customProcessor.CurrentComponentDatas);
            Assert.False(customProcessor.CurrentComponentDatas.ContainsKey(customComponent2));

            Assert.Null(customComponent2.Entity);
            expectedEvents = new List <CustomEntityComponentEventArgs>()
            {
                new CustomEntityComponentEventArgs(CustomEntityComponentEventType.EntityComponentRemoved, entity, customComponent2),
            };
            Assert.Equal(expectedEvents, events);
            events.Clear();

            // The processor is still registered but is not running on any component
            Assert.Equal(2, entityManager.Processors.Count);
            Assert.NotNull(entityManager.GetProcessor <CustomEntityComponentProcessor>());
        }
예제 #8
0
        public void Benchmark()
        {
            const int TestCount       = 5;
            const int TestEntityCount = 10000;

            long totalTime = 0;
            long stepTime  = 0;
            var  clock     = Stopwatch.StartNew();

            Console.WriteLine($"Test1 -> [Add {TestEntityCount} entities + 10 custom components] x {TestCount} times");
            Console.WriteLine($"Test2 -> [Add {TestEntityCount} entities], [Add 10 custom component, Remove 10 custom component] x {TestCount} times)");

            DumpGC($"Start Test1 - ");
            for (int j = 0; j < TestCount; j++)
            {
                var registry      = new ServiceRegistry();
                var entityManager = new CustomEntityManager(registry);

                clock.Restart();
                for (int i = 0; i < TestEntityCount; i++)
                {
                    var entity = new Entity
                    {
                        new BenchComponent1(),
                        new BenchComponent2(),
                        new BenchComponent3(),
                        new BenchComponent4(),
                        new BenchComponent5(),
                        new BenchComponent6(),
                        new BenchComponent7(),
                        new BenchComponent8(),
                        new BenchComponent9(),
                        new BenchComponent10(),
                    };

                    entityManager.Add(entity);
                }
                var elapsed = clock.ElapsedMilliseconds;
                stepTime += elapsed;
                DumpGC($"\t[{j}] Elapsed: {elapsed}ms ");
            }
            DumpGC($"End - Elapsed {stepTime}ms ");
            totalTime += stepTime;
            stepTime   = 0;

            Console.WriteLine();

            DumpGC($"Start Test2 - ");
            {
                var registry      = new ServiceRegistry();
                var entityManager = new CustomEntityManager(registry);

                for (int i = 0; i < TestEntityCount; i++)
                {
                    var entity = new Entity();
                    entityManager.Add(entity);
                }

                for (int j = 0; j < TestCount; j++)
                {
                    clock.Restart();
                    foreach (var entity in entityManager)
                    {
                        entity.Add(new BenchComponent1());
                        entity.Add(new BenchComponent2());
                        entity.Add(new BenchComponent3());
                        entity.Add(new BenchComponent4());
                        entity.Add(new BenchComponent5());
                        entity.Add(new BenchComponent6());
                        entity.Add(new BenchComponent7());
                        entity.Add(new BenchComponent8());
                        entity.Add(new BenchComponent9());
                        entity.Add(new BenchComponent10());
                    }
                    var elapsedAdd = clock.ElapsedMilliseconds;
                    stepTime += elapsedAdd;
                    clock.Restart();

                    foreach (var entity in entityManager)
                    {
                        entity.Remove <BenchComponent1>();
                        entity.Remove <BenchComponent2>();
                        entity.Remove <BenchComponent3>();
                        entity.Remove <BenchComponent4>();
                        entity.Remove <BenchComponent5>();
                        entity.Remove <BenchComponent6>();
                        entity.Remove <BenchComponent7>();
                        entity.Remove <BenchComponent8>();
                        entity.Remove <BenchComponent9>();
                        entity.Remove <BenchComponent10>();
                    }

                    var elapsedRemove = clock.ElapsedMilliseconds;
                    stepTime += elapsedRemove;
                    DumpGC($"\t[{j}] ElapsedAdd: {elapsedAdd} ElapsedRemove: {elapsedRemove} ");
                }
            }
            DumpGC($"End - Elapsed {stepTime}ms ");
            totalTime += stepTime;

            // Only perform this assert on Windows
            if (Platform.Type == PlatformType.Windows)
            {
                Assert.True(totalTime < 3000, "This test should run in less than 3000ms");
            }

            Console.WriteLine($"Total Time: {totalTime}ms");
        }