From 3b6d473aeb4af62b1cab1f85231c5c68d17405a0 Mon Sep 17 00:00:00 2001 From: thatcosmonaut Date: Wed, 13 Nov 2019 13:24:20 -0800 Subject: [PATCH] implement runtime type GetComponent --- encompass-cs/ComponentMessageManager.cs | 24 +++++++++++++ encompass-cs/Engine.cs | 46 +++++++++++++++++++++++++ test/ComponentTest.cs | 38 ++++++++++++++++++++ 3 files changed, 108 insertions(+) diff --git a/encompass-cs/ComponentMessageManager.cs b/encompass-cs/ComponentMessageManager.cs index 3cde86c..8541880 100644 --- a/encompass-cs/ComponentMessageManager.cs +++ b/encompass-cs/ComponentMessageManager.cs @@ -249,6 +249,18 @@ namespace Encompass } } + internal (Guid, IComponent) ReadExistingComponentByEntityAndType(Entity entity, Type type) + { + if (entityToTypeToExistingComponentID.ContainsKey(entity) && entityToTypeToExistingComponentID[entity].TryGetValue(type, out Guid id)) + { + return (id, componentIDToComponent[id]); + } + else + { + throw new NoComponentOfTypeOnEntityException("No Component of type {0} exists on Entity {1}", type.Name, entity.ID); + } + } + internal (Guid, TComponent) ReadPendingComponentByEntityAndType(Entity entity) where TComponent : struct, IComponent { if (entityToTypeToPendingComponentID.ContainsKey(entity) && entityToTypeToPendingComponentID[entity].TryGetValue(typeof(TComponent), out Guid id)) @@ -261,6 +273,18 @@ namespace Encompass } } + internal (Guid, IComponent) ReadPendingComponentByEntityAndType(Entity entity, Type type) + { + if (entityToTypeToPendingComponentID.ContainsKey(entity) && entityToTypeToPendingComponentID[entity].TryGetValue(type, out Guid id)) + { + return (id, componentIDToComponent[id]); + } + else + { + throw new NoComponentOfTypeOnEntityException("No Component of type {0} exists on Entity {1}", type.Name, entity.ID); + } + } + // check if entity has component of type internal bool HasExistingOrPendingComponent(Entity entity) where TComponent : struct, IComponent diff --git a/encompass-cs/Engine.cs b/encompass-cs/Engine.cs index c68184f..4c57a00 100644 --- a/encompass-cs/Engine.cs +++ b/encompass-cs/Engine.cs @@ -333,6 +333,52 @@ namespace Encompass } } + /// + /// Returns a Component with the specified Type that exists on the Entity. + /// + /// + /// Thrown when the Entity does not have a Component of the specified Type + /// + /// + /// Thrown when the Engine does not declare that it reads the given Component Type. + /// + protected (Guid, IComponent) GetComponent(Entity entity, Type type) + { + var pending = typeof(PendingComponentMessage<>).MakeGenericType(type); + var existing = typeof(ComponentMessage<>).MakeGenericType(type); + + var pendingRead = receiveTypes.Contains(pending); + var existingRead = receiveTypes.Contains(existing); + + if (existingRead && pendingRead) + { + if (componentMessageManager.HasPendingComponent(entity, pending)) + { + return componentMessageManager.ReadPendingComponentByEntityAndType(entity, pending); + } + else if (componentMessageManager.HasExistingComponent(entity, existing)) + { + return componentMessageManager.ReadExistingComponentByEntityAndType(entity, existing); + } + else + { + throw new NoComponentOfTypeOnEntityException("No Component of type {0} exists on Entity {1}", type.Name, entity.ID); + } + } + else if (existingRead) + { + return componentMessageManager.ReadExistingComponentByEntityAndType(entity, existing); + } + else if (pendingRead) + { + return componentMessageManager.ReadPendingComponentByEntityAndType(entity, pending); + } + else + { + throw new IllegalReadException("Engine {0} tried to read undeclared Component {1}", GetType().Name, type.Name); + } + } + /// /// Returns true if the Entity has a Component of the given Type. /// diff --git a/test/ComponentTest.cs b/test/ComponentTest.cs index 4ae154a..cdc124c 100644 --- a/test/ComponentTest.cs +++ b/test/ComponentTest.cs @@ -271,6 +271,44 @@ namespace Tests Assert.AreEqual((componentID, mockComponent), gottenMockComponentIDPair); } + [Receives(typeof(EntityMessage))] + [Reads(typeof(MockComponent))] + class GetMockComponentByRuntimeType : Engine + { + public override void Update(double dt) + { + foreach (var entityMessage in ReadMessages()) + { + gottenMockComponentIDPair = ((Guid, MockComponent))GetComponent(entityMessage.entity, typeof(MockComponent)); + } + } + } + + [Test] + public void GetComponentByRuntimeType() + { + var worldBuilder = new WorldBuilder(); + worldBuilder.AddEngine(new GetMockComponentEngine()); + + var entity = worldBuilder.CreateEntity(); + + MockComponent mockComponent; + mockComponent.myInt = 3; + mockComponent.myString = "hello"; + + var componentID = worldBuilder.SetComponent(entity, mockComponent); + + EntityMessage entityMessage; + entityMessage.entity = entity; + worldBuilder.SendMessage(entityMessage); + + var world = worldBuilder.Build(); + + world.Update(0.01); + + Assert.AreEqual((componentID, mockComponent), gottenMockComponentIDPair); + } + struct HasComponentTestMessage : IMessage { public Entity entity;