component update mechanism
parent
4b9610762a
commit
cb872b7c42
|
@ -5,6 +5,7 @@ using System.Linq;
|
||||||
namespace Encompass {
|
namespace Encompass {
|
||||||
internal class ComponentManager {
|
internal class ComponentManager {
|
||||||
private Dictionary<uint, List<IComponent>> entityIDToComponents = new Dictionary<uint, List<IComponent>>();
|
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>> activeComponents = new Dictionary<Type, List<IComponent>>();
|
||||||
private Dictionary<Type, List<IComponent>> inactiveComponents = 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);
|
entityIDToComponents[entityID].Add(component);
|
||||||
|
componentToEntityID[component] = entityID;
|
||||||
|
|
||||||
if (!activeComponents.ContainsKey(typeof(TComponent))) {
|
if (!activeComponents.ContainsKey(typeof(TComponent))) {
|
||||||
activeComponents.Add(typeof(TComponent), new List<IComponent>());
|
activeComponents.Add(typeof(TComponent), new List<IComponent>());
|
||||||
|
@ -50,6 +52,37 @@ namespace Encompass {
|
||||||
return GetComponentsByEntityAndType<TComponent>(entityID).Any();
|
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) {
|
internal void RemoveAllComponentsFromEntity(uint entityID) {
|
||||||
var components = GetComponentsByEntity(entityID);
|
var components = GetComponentsByEntity(entityID);
|
||||||
|
|
||||||
|
@ -65,6 +98,10 @@ namespace Encompass {
|
||||||
componentsToActivate.Add(component);
|
componentsToActivate.Add(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void MarkForDeactivation(IComponent component) {
|
||||||
|
componentsToDeactivate.Add(component);
|
||||||
|
}
|
||||||
|
|
||||||
internal void MarkForRemoval(IComponent component) {
|
internal void MarkForRemoval(IComponent component) {
|
||||||
componentsToRemove.Add(component);
|
componentsToRemove.Add(component);
|
||||||
}
|
}
|
||||||
|
@ -78,6 +115,13 @@ namespace Encompass {
|
||||||
componentsToActivate.Clear();
|
componentsToActivate.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void DeactivateComponents() {
|
||||||
|
foreach (var component in componentsToDeactivate) {
|
||||||
|
activeComponents[component.GetType()].Remove(component);
|
||||||
|
inactiveComponents[component.GetType()].Add(component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal void RemoveComponents() {
|
internal void RemoveComponents() {
|
||||||
foreach (var component in componentsToRemove) {
|
foreach (var component in componentsToRemove) {
|
||||||
activeComponents[component.GetType()].Remove(component);
|
activeComponents[component.GetType()].Remove(component);
|
||||||
|
|
|
@ -1,10 +1,21 @@
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Encompass {
|
namespace Encompass {
|
||||||
public abstract class Engine {
|
public abstract class Engine {
|
||||||
|
public readonly List<Type> mutateComponentTypes = new List<Type>();
|
||||||
|
|
||||||
private EntityManager entityManager;
|
private EntityManager entityManager;
|
||||||
private ComponentManager componentManager;
|
private ComponentManager componentManager;
|
||||||
|
|
||||||
|
public Engine() {
|
||||||
|
var mutatesAttribute = this.GetType().GetCustomAttribute<Mutates>(false);
|
||||||
|
if (mutatesAttribute != null) {
|
||||||
|
mutateComponentTypes = mutatesAttribute.mutateComponentTypes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal void AssignEntityManager(EntityManager entityManager) {
|
internal void AssignEntityManager(EntityManager entityManager) {
|
||||||
this.entityManager = entityManager;
|
this.entityManager = entityManager;
|
||||||
}
|
}
|
||||||
|
@ -26,5 +37,13 @@ namespace Encompass {
|
||||||
protected TComponent ReadComponent<TComponent>() where TComponent : struct, IComponent {
|
protected TComponent ReadComponent<TComponent>() where TComponent : struct, IComponent {
|
||||||
return this.componentManager.GetActiveComponentByType<TComponent>();
|
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="ComponentManager.cs" />
|
||||||
<Content Include="WorldBuilder.cs" />
|
<Content Include="WorldBuilder.cs" />
|
||||||
<Content Include="Engine.cs" />
|
<Content Include="Engine.cs" />
|
||||||
|
<Content Include="attributes\Mutates.cs" />
|
||||||
|
<Content Include="exceptions\IllegalComponentMutationException.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</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));
|
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