component update mechanism
							parent
							
								
									4b9610762a
								
							
						
					
					
						commit
						cb872b7c42
					
				| 
						 | 
				
			
			@ -5,6 +5,7 @@ using System.Linq;
 | 
			
		|||
namespace Encompass {
 | 
			
		||||
    internal class ComponentManager {
 | 
			
		||||
        private Dictionary<uint, List<IComponent>> entityIDToComponents = new Dictionary<uint, List<IComponent>>();
 | 
			
		||||
        private Dictionary<IComponent, uint> componentToEntityID = new Dictionary<IComponent, uint>();
 | 
			
		||||
 | 
			
		||||
        private Dictionary<Type, List<IComponent>> activeComponents = new Dictionary<Type, List<IComponent>>();
 | 
			
		||||
        private Dictionary<Type, List<IComponent>> inactiveComponents = new Dictionary<Type, List<IComponent>>();
 | 
			
		||||
| 
						 | 
				
			
			@ -19,6 +20,7 @@ namespace Encompass {
 | 
			
		|||
            }
 | 
			
		||||
 | 
			
		||||
            entityIDToComponents[entityID].Add(component);
 | 
			
		||||
            componentToEntityID[component] = entityID;
 | 
			
		||||
 | 
			
		||||
            if (!activeComponents.ContainsKey(typeof(TComponent))) {
 | 
			
		||||
                activeComponents.Add(typeof(TComponent), new List<IComponent>());
 | 
			
		||||
| 
						 | 
				
			
			@ -50,6 +52,37 @@ namespace Encompass {
 | 
			
		|||
            return GetComponentsByEntityAndType<TComponent>(entityID).Any();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /** Replaces the component with another. */
 | 
			
		||||
        internal void UpdateComponent<TComponent>(TComponent originalComponent, TComponent newComponent) where TComponent : struct, IComponent {
 | 
			
		||||
            var entityID = componentToEntityID[originalComponent];
 | 
			
		||||
 | 
			
		||||
            entityIDToComponents[entityID].Remove(originalComponent);
 | 
			
		||||
            entityIDToComponents[entityID].Add(newComponent);
 | 
			
		||||
 | 
			
		||||
            componentToEntityID.Remove(originalComponent);
 | 
			
		||||
            componentToEntityID.Add(newComponent, entityID);
 | 
			
		||||
 | 
			
		||||
            if (activeComponents[originalComponent.GetType()].Remove(originalComponent)) {
 | 
			
		||||
                activeComponents[originalComponent.GetType()].Add(newComponent);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (inactiveComponents[originalComponent.GetType()].Remove(originalComponent)) {
 | 
			
		||||
                inactiveComponents[originalComponent.GetType()].Add(newComponent);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (componentsToActivate.Remove(originalComponent)) {
 | 
			
		||||
                componentsToActivate.Add(newComponent);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (componentsToDeactivate.Remove(originalComponent)) {
 | 
			
		||||
                componentsToDeactivate.Add(newComponent);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (componentsToRemove.Remove(originalComponent)) {
 | 
			
		||||
                componentsToRemove.Add(newComponent);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        internal void RemoveAllComponentsFromEntity(uint entityID) {
 | 
			
		||||
            var components = GetComponentsByEntity(entityID);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -65,6 +98,10 @@ namespace Encompass {
 | 
			
		|||
            componentsToActivate.Add(component);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        internal void MarkForDeactivation(IComponent component) {
 | 
			
		||||
            componentsToDeactivate.Add(component);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        internal void MarkForRemoval(IComponent component) {
 | 
			
		||||
            componentsToRemove.Add(component);
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -78,6 +115,13 @@ namespace Encompass {
 | 
			
		|||
            componentsToActivate.Clear();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        internal void DeactivateComponents() {
 | 
			
		||||
            foreach (var component in componentsToDeactivate) {
 | 
			
		||||
                activeComponents[component.GetType()].Remove(component);
 | 
			
		||||
                inactiveComponents[component.GetType()].Add(component);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        internal void RemoveComponents() {
 | 
			
		||||
            foreach (var component in componentsToRemove) {
 | 
			
		||||
                activeComponents[component.GetType()].Remove(component);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,10 +1,21 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Encompass {
 | 
			
		||||
    public abstract class Engine {
 | 
			
		||||
        public readonly List<Type> mutateComponentTypes = new List<Type>();
 | 
			
		||||
 | 
			
		||||
        private EntityManager entityManager;
 | 
			
		||||
        private ComponentManager componentManager;
 | 
			
		||||
 | 
			
		||||
        public Engine() {
 | 
			
		||||
            var mutatesAttribute = this.GetType().GetCustomAttribute<Mutates>(false);
 | 
			
		||||
            if (mutatesAttribute != null) {
 | 
			
		||||
                mutateComponentTypes = mutatesAttribute.mutateComponentTypes;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        internal void AssignEntityManager(EntityManager entityManager) {
 | 
			
		||||
            this.entityManager = entityManager;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -26,5 +37,13 @@ namespace Encompass {
 | 
			
		|||
        protected TComponent ReadComponent<TComponent>() where TComponent : struct, IComponent {
 | 
			
		||||
            return this.componentManager.GetActiveComponentByType<TComponent>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected void UpdateComponent<TComponent>(TComponent originalComponent, TComponent newComponent) where TComponent : struct, IComponent {
 | 
			
		||||
            if (mutateComponentTypes.Contains(typeof(TComponent))) {
 | 
			
		||||
                this.componentManager.UpdateComponent(originalComponent, newComponent);
 | 
			
		||||
            } else {
 | 
			
		||||
                throw new IllegalComponentMutationException("Engine {0} tried to mutate undeclared Component {1}", this.GetType().ToString(), typeof(TComponent).ToString());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Encompass {
 | 
			
		||||
    [System.AttributeUsage(System.AttributeTargets.Class)]
 | 
			
		||||
    public class Mutates : System.Attribute
 | 
			
		||||
    {
 | 
			
		||||
        public readonly List<Type> mutateComponentTypes;
 | 
			
		||||
 | 
			
		||||
        public Mutates(params Type[] mutateComponentTypes)
 | 
			
		||||
        {
 | 
			
		||||
            this.mutateComponentTypes = new List<Type>(mutateComponentTypes);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -13,5 +13,7 @@
 | 
			
		|||
    <Content Include="ComponentManager.cs" />
 | 
			
		||||
    <Content Include="WorldBuilder.cs" />
 | 
			
		||||
    <Content Include="Engine.cs" />
 | 
			
		||||
    <Content Include="attributes\Mutates.cs" />
 | 
			
		||||
    <Content Include="exceptions\IllegalComponentMutationException.cs" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
</Project>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Encompass {
 | 
			
		||||
    public class IllegalComponentMutationException : Exception {
 | 
			
		||||
        public IllegalComponentMutationException(
 | 
			
		||||
            string format,
 | 
			
		||||
            params object[] args
 | 
			
		||||
        ) : base(string.Format(format, args)) { }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -98,5 +98,73 @@ namespace Tests {
 | 
			
		|||
 | 
			
		||||
            Assert.Throws<InvalidOperationException>(() => world.Update(0.01f));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Mutates(typeof(MockComponent))]
 | 
			
		||||
        public class UpdateComponentTestEngine : Engine
 | 
			
		||||
        {
 | 
			
		||||
            public override void Update(float dt)
 | 
			
		||||
            {
 | 
			
		||||
                var originalComponent = this.ReadComponent<MockComponent>();
 | 
			
		||||
                var newComponent = this.ReadComponent<MockComponent>();
 | 
			
		||||
                newComponent.myInt = 420;
 | 
			
		||||
                newComponent.myString = "blaze it";
 | 
			
		||||
                this.UpdateComponent(originalComponent, newComponent);
 | 
			
		||||
                component = this.ReadComponent<MockComponent>();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        public void UpdateComponent()
 | 
			
		||||
        {
 | 
			
		||||
            var worldBuilder = new WorldBuilder();
 | 
			
		||||
            worldBuilder.AddEngine<UpdateComponentTestEngine>();
 | 
			
		||||
 | 
			
		||||
            var entity = worldBuilder.CreateEntity();
 | 
			
		||||
 | 
			
		||||
            MockComponent mockComponent;
 | 
			
		||||
            mockComponent.myInt = 0;
 | 
			
		||||
            mockComponent.myString = "hello";
 | 
			
		||||
 | 
			
		||||
            entity.AddComponent(mockComponent);
 | 
			
		||||
 | 
			
		||||
            var world = worldBuilder.Build();
 | 
			
		||||
 | 
			
		||||
            world.Update(0.01f);
 | 
			
		||||
 | 
			
		||||
            Assert.AreEqual(420, component.myInt);
 | 
			
		||||
            Assert.AreEqual("blaze it", component.myString);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public class UndeclaredUpdateComponentTestEngine : Engine
 | 
			
		||||
        {
 | 
			
		||||
            public override void Update(float dt)
 | 
			
		||||
            {
 | 
			
		||||
                var originalComponent = this.ReadComponent<MockComponent>();
 | 
			
		||||
                var newComponent = this.ReadComponent<MockComponent>();
 | 
			
		||||
                newComponent.myInt = 420;
 | 
			
		||||
                newComponent.myString = "blaze it";
 | 
			
		||||
                this.UpdateComponent(originalComponent, newComponent);
 | 
			
		||||
                component = this.ReadComponent<MockComponent>();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Test]
 | 
			
		||||
        public void UpdateUndeclaredComponent()
 | 
			
		||||
        {
 | 
			
		||||
            var worldBuilder = new WorldBuilder();
 | 
			
		||||
            worldBuilder.AddEngine<UndeclaredUpdateComponentTestEngine>();
 | 
			
		||||
 | 
			
		||||
            var entity = worldBuilder.CreateEntity();
 | 
			
		||||
 | 
			
		||||
            MockComponent mockComponent;
 | 
			
		||||
            mockComponent.myInt = 0;
 | 
			
		||||
            mockComponent.myString = "hello";
 | 
			
		||||
 | 
			
		||||
            entity.AddComponent(mockComponent);
 | 
			
		||||
 | 
			
		||||
            var world = worldBuilder.Build();
 | 
			
		||||
 | 
			
		||||
            Assert.Throws<IllegalComponentMutationException>(() => world.Update(0.01f));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue