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); }
private CameraComponent AddCamera(bool enabled, SceneCameraSlotId slot) { var camera = new CameraComponent { Enabled = enabled, Slot = slot }; entityManager.Add(new Entity { camera }); return(camera); }
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); }
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); }
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); }
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(); }
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>()); }
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"); }