Browse Source

Added PlanComponentManager; Small Refactoring

- Added PlanComponentManager, which is still WIP but at a stage where it could be used in Galavant-Unreal
- Removed all functions with (void) because apparently that's just a C thing (what I use I work) and is discouraged in C++
- Removed some #ifdef include guards in favor of #pragma once
- Put some earlier code into the Galavant gv namespace 
- Fixed a small bug in EntityTypes.cpp where EntityListAppend() was actually prepending (oops!)
- Started writing WorldState. This class is likely to see lots of refactoring
- Tried some geo stuff out in BuildingSystem
combatComponentRefactor
Macoy Madson 7 years ago
parent
commit
8063ccc2ad
  1. BIN
      assets/models/BuildingSystem.blend
  2. 26
      src/ai/WorldState.hpp
  3. 35
      src/ai/htn/HTNPlanner.cpp
  4. 25
      src/ai/htn/HTNPlanner.hpp
  5. 14
      src/ai/htn/HTNTasks.cpp
  6. 27
      src/ai/htn/HTNTasks.hpp
  7. 4
      src/ai/htn/HTNTypes.hpp
  8. 5
      src/entityComponentSystem/ComponentManager.cpp
  9. 10
      src/entityComponentSystem/ComponentManager.hpp
  10. 7
      src/entityComponentSystem/EntityComponentManager.cpp
  11. 12
      src/entityComponentSystem/EntityComponentManager.hpp
  12. 6
      src/entityComponentSystem/EntityTypes.cpp
  13. 7
      src/entityComponentSystem/EntityTypes.hpp
  14. 33
      src/entityComponentSystem/PooledComponentManager.hpp
  15. 2
      src/experiments/flatbuffers/testFlatbuffers_WriteOut.cpp
  16. 5
      src/game/Jamfile
  17. 80
      src/game/agent/PlanComponentManager.cpp
  18. 39
      src/game/agent/PlanComponentManager.hpp
  19. 10
      src/unitTesting/EntityComponentSystem_test.cpp
  20. 28
      src/unitTesting/HTN_test.cpp
  21. 11
      src/util/FragmentedPool.hpp
  22. 10
      src/util/ObjectPool.hpp

BIN
assets/models/BuildingSystem.blend

Binary file not shown.

26
src/ai/WorldState.hpp

@ -0,0 +1,26 @@
#pragma once
#include "../world/Position.hpp"
namespace gv
{
struct AgentState
{
Position position;
};
/* --WorldState--
WorldState represents a mutable, copyable reference to all AI-relevant data in the World.
Mutable: The data can be manipulated freely without repurcussion. Note that changing data in
WorldState is NOT expected to actually change the world - WorldState is like a mirror world
Copyable: The data can be copied without a significant amount of time. This means that in order
to support mutability, things like changelists might need to be implemented for large datasets
instead of actually copying the dataset
*/
struct WorldState
{
// Because an agent is almost always going to...well, maybe this shouldn't be here. For now it
// will stay.
AgentState SourceAgent;
};
};

35
src/ai/htn/HTNPlanner.cpp

@ -36,10 +36,20 @@ bool DecomposeCompoundTask(TaskCallList& compoundDecompositions, CompoundTask* c
return compoundTask->Decompose(compoundDecompositions, state, parameters);
}
bool Planner::IsPlanRunning()
{
return IsPlanRunning(CurrentStatus);
}
bool Planner::IsPlanRunning(Status status)
{
return (status > Status::Running_EnumBegin && status < Status::Running_EnumEnd);
}
// When the stack is empty, find a goal task to push onto the task or add tasks as per usual
// If any Decompositions or Preconditions fail, we must fail the entire plan because we have
// no alternate methods
Planner::Status Planner::PlanStep_BottomLevel(void)
Planner::Status Planner::PlanStep_BottomLevel()
{
if (InitialCallList.empty())
return Status::Failed_NoTasks;
@ -57,7 +67,7 @@ Planner::Status Planner::PlanStep_BottomLevel(void)
if (DebugPrint)
{
std::cout << "\nPlanStep()\nWorkingCallList.size() = " << WorkingCallList.size() << "\n";
printTaskCallList(WorkingCallList);
PrintTaskCallList(WorkingCallList);
}
for (TaskCallListIterator currentTaskCallIter = WorkingCallList.begin();
@ -156,7 +166,7 @@ Planner::Status Planner::PlanStep_BottomLevel(void)
return Status::PlanComplete;
}
Planner::Status Planner::PlanStep_StackFrame(void)
Planner::Status Planner::PlanStep_StackFrame()
{
// Remember: If goal fails to decompose and goal is bottom of stack, fail
GoalDecompositionStack::iterator currentStackFrameIter = DecompositionStack.end() - 1;
@ -166,7 +176,7 @@ Planner::Status Planner::PlanStep_StackFrame(void)
{
std::cout << "\nPlanStep()\ncurrentStackFrame.CallList.size() = "
<< currentStackFrame.CallList.size() << "\n";
printTaskCallList(currentStackFrame.CallList);
PrintTaskCallList(currentStackFrame.CallList);
std::cout << "Stack Depth: ";
for (unsigned int i = 0; i < DecompositionStack.size(); i++)
@ -176,12 +186,12 @@ Planner::Status Planner::PlanStep_StackFrame(void)
{
std::cout << "----Fullstack working lists\n";
std::cout << "[0]\n";
printTaskCallList(WorkingCallList);
PrintTaskCallList(WorkingCallList);
int i = 1;
for (GoalDecomposition& stackFrame : DecompositionStack)
{
std::cout << "[" << i++ << "]\n";
printTaskCallList(stackFrame.CallList);
PrintTaskCallList(stackFrame.CallList);
}
std::cout << "----\n";
}
@ -318,7 +328,7 @@ Planner::Status Planner::PlanStep_StackFrame(void)
std::cout << "currentStackFrame.CallList.size() = "
<< currentStackFrame.CallList.size() << "\n";
std::cout << "Decomposition:\n";
printTaskCallList(compoundDecompositions);
PrintTaskCallList(compoundDecompositions);
}
currentStackFrame.CallList.insert(currentStackFrame.CallList.begin(),
compoundDecompositions.begin(),
@ -360,9 +370,9 @@ Planner::Status Planner::PlanStep_StackFrame(void)
if (DebugPrint)
{
std::cout << "Collapsing stack frame. Adding List:\n";
printTaskCallList(currentStackFrame.FinalCallList);
PrintTaskCallList(currentStackFrame.FinalCallList);
std::cout << "To parent:\n";
printTaskCallList(*parentFinalCallList);
PrintTaskCallList(*parentFinalCallList);
}
parentFinalCallList->insert(parentFinalCallList->end(),
@ -385,7 +395,7 @@ Planner::Status Planner::PlanStep_StackFrame(void)
// TODO: Pool various task lists?
// TODO: Pull more things out into functions, if possible. It's bad that whenever I make a change to
// something I have to change it in two places
Planner::Status Planner::PlanStep(void)
Planner::Status Planner::PlanStep()
{
Status status = Status::Failed_NoPossiblePlan;
@ -407,10 +417,11 @@ Planner::Status Planner::PlanStep(void)
status == Status::Running_FailedGoalDecomposition)) ||
(BreakOnFailedDecomposition && (status == Status::Running_FailedGoalDecomposition ||
status == Status::Running_FailedMethodDecomposition)))
return status;
break;
} while (status >= Status::Running_EnumBegin && status <= Status::Running_EnumEnd);
} while (IsPlanRunning(status));
CurrentStatus = status;
return status;
}
}

25
src/ai/htn/HTNPlanner.hpp

@ -2,6 +2,7 @@
#include "HTNTypes.hpp"
#include "HTNTasks.hpp"
#include "../WorldState.hpp"
namespace Htn
{
@ -29,11 +30,20 @@ struct GoalDecomposition
typedef std::vector<GoalDecomposition> GoalDecompositionStack;
// TODO: Either make planner allow making multiple plans with the same instance, or make it clear
// that it is for a single plan only
/* -- Planner --
Given the world state and a set of goal tasks, decompose them into a list of primitive tasks which,
when executed, will result in the desired goal tasks being completed. Note that the initial goal
task set can include compound and primitive tasks.
TODO: Either make planner allow making multiple plans with the same instance, or make it clear
that it is for a single plan only
*/
class Planner
{
public:
Planner() = default;
~Planner() = default;
WorldState State;
TaskCallList InitialCallList;
@ -79,7 +89,12 @@ public:
PlanComplete
};
Status PlanStep(void);
bool IsPlanRunning();
bool IsPlanRunning(Status status);
Status CurrentStatus;
Status PlanStep();
private:
GoalDecompositionStack DecompositionStack;
@ -90,7 +105,7 @@ private:
// Copy of InitialCallList that Planner can fuck with
TaskCallList WorkingCallList;
Status PlanStep_StackFrame(void);
Status PlanStep_BottomLevel(void);
Status PlanStep_StackFrame();
Status PlanStep_BottomLevel();
};
};

14
src/ai/htn/HTNTasks.cpp

@ -5,7 +5,7 @@
namespace Htn
{
int GoalTask::GetNumMethods(void)
int GoalTask::GetNumMethods()
{
return Methods ? Methods->size() : 0;
}
@ -53,22 +53,22 @@ Task::Task(PrimitiveTask* primitive)
Type = TaskType::Primitive;
}
TaskType Task::GetType(void) const
TaskType Task::GetType() const
{
return Type;
}
GoalTask* Task::GetGoal(void)
GoalTask* Task::GetGoal()
{
assert(Type == TaskType::Goal);
return Goal;
}
CompoundTask* Task::GetCompound(void)
CompoundTask* Task::GetCompound()
{
assert(Type == TaskType::Compound);
return Compound;
}
PrimitiveTask* Task::GetPrimitive(void)
PrimitiveTask* Task::GetPrimitive()
{
assert(Type == TaskType::Primitive);
return Primitive;
@ -94,7 +94,7 @@ std::ostream& operator<<(std::ostream& os, const Task& task)
return os;
}
void printTaskList(const TaskList& tasks)
void PrintTaskList(const TaskList& tasks)
{
std::cout << "TaskList size = " << tasks.size() << " addr " << &tasks << ":\n";
for (unsigned int i = 0; i < tasks.size(); i++)
@ -103,7 +103,7 @@ void printTaskList(const TaskList& tasks)
}
}
void printTaskCallList(const TaskCallList& tasks)
void PrintTaskCallList(const TaskCallList& tasks)
{
std::cout << "TaskCallList size = " << tasks.size() << " addr " << &tasks << ":\n";
for (unsigned int i = 0; i < tasks.size(); i++)

27
src/ai/htn/HTNTasks.hpp

@ -1,6 +1,7 @@
#pragma once
#include "HTNTypes.hpp"
#include "../WorldState.hpp"
#include <iostream>
@ -28,9 +29,9 @@ private:
TaskList* Methods;
public:
GoalTask(void) = default;
GoalTask() = default;
int GetNumMethods(void);
int GetNumMethods();
Task* GetMethodAtIndex(int index);
bool DecomposeMethodAtIndex(TaskCallList& decomposition, int index,
@ -42,8 +43,8 @@ public:
class CompoundTask
{
public:
CompoundTask(void) = default;
virtual ~CompoundTask(void) = default;
CompoundTask() = default;
virtual ~CompoundTask() = default;
virtual bool StateMeetsPreconditions(const WorldState& state,
const ParameterList& parameters) const = 0;
virtual bool Decompose(TaskCallList& taskCallList, const WorldState& state,
@ -53,8 +54,8 @@ public:
class PrimitiveTask
{
public:
PrimitiveTask(void) = default;
virtual ~PrimitiveTask(void) = default;
PrimitiveTask() = default;
virtual ~PrimitiveTask() = default;
virtual bool StateMeetsPreconditions(const WorldState& state,
const ParameterList& parameters) const = 0;
virtual void ApplyStateChange(WorldState& state, const ParameterList& parameters) = 0;
@ -76,16 +77,16 @@ enum class TaskType
// only allow only one thing to be filled in for it
struct Task
{
Task(void) = delete;
Task() = delete;
Task(GoalTask* goal);
Task(CompoundTask* compound);
Task(PrimitiveTask* primitive);
TaskType GetType(void) const;
TaskType GetType() const;
GoalTask* GetGoal(void);
CompoundTask* GetCompound(void);
PrimitiveTask* GetPrimitive(void);
GoalTask* GetGoal();
CompoundTask* GetCompound();
PrimitiveTask* GetPrimitive();
friend std::ostream& operator<<(std::ostream& os, const Task& task);
@ -102,6 +103,6 @@ private:
std::ostream& operator<<(std::ostream& os, const Task& task);
void printTaskList(const TaskList& tasks);
void printTaskCallList(const TaskCallList& tasks);
void PrintTaskList(const TaskList& tasks);
void PrintTaskCallList(const TaskCallList& tasks);
}

4
src/ai/htn/HTNTypes.hpp

@ -29,7 +29,7 @@ struct Parameter
float FloatValue;
bool BoolValue;
Entity EntityValue;
gv::Entity EntityValue;
};
};
@ -39,5 +39,5 @@ typedef std::vector<Parameter>::const_iterator ParameterListConstIterator;
typedef std::vector<Parameter>::reverse_iterator ParameterListReverseIterator;
// The arguments passed to most all Task functions
typedef int WorldState; // TODO
typedef int WorldState; // TODO: replace with AI WorldState from WorldState.hpp
}

5
src/entityComponentSystem/ComponentManager.cpp

@ -1,5 +1,7 @@
#include "ComponentManager.hpp"
namespace gv
{
ComponentManager::~ComponentManager()
{
}
@ -8,7 +10,8 @@ void ComponentManager::UnsubscribeEntities(const EntityList& entities)
{
}
ComponentType ComponentManager::GetType(void)
ComponentType ComponentManager::GetType()
{
return Type;
}
}

10
src/entityComponentSystem/ComponentManager.hpp

@ -1,8 +1,9 @@
#ifndef COMPONENTMANAGER_H__
#define COMPONENTMANAGER_H__
#pragma once
#include "EntityTypes.hpp"
namespace gv
{
// Base class for all ComponentManagers. Note that it is intended to be a very minimal interface
// because the Entity Component System is designed to be minimally polymorphic. This is so it is
// more obvious when things happen. It also reduces the amount of boilerplate needed when creating a
@ -10,6 +11,7 @@
class ComponentManager
{
protected:
// You should set this type in your constructor
ComponentType Type;
public:
@ -17,7 +19,7 @@ public:
virtual void UnsubscribeEntities(const EntityList& entities);
ComponentType GetType(void);
ComponentType GetType();
};
#endif /* end of include guard: COMPONENTMANAGER_H__ */
};

7
src/entityComponentSystem/EntityComponentManager.cpp

@ -1,5 +1,7 @@
#include "EntityComponentManager.hpp"
namespace gv
{
Entity EntityComponentManager::NextNewEntity = 1;
EntityComponentManager::EntityComponentManager()
@ -80,7 +82,7 @@ void EntityComponentManager::UnsubscribeEntitiesFromAllManagers(EntityList &enti
// Destroy all entities which have been marked for destruction. Because an entity is just an ID
// and a collection of components, this function must notify all ComponentManagers that the
// Entity should be unsubscribed from their services.
void EntityComponentManager::DestroyEntitiesPendingDestruction(void)
void EntityComponentManager::DestroyEntitiesPendingDestruction()
{
if (!EntitiesPendingDestruction.empty())
{
@ -98,7 +100,7 @@ void EntityComponentManager::DestroyEntitiesPendingDestruction(void)
// Destroys all entities that were created by this EntityComponentManager (i.e. all entities in
// the ActiveEntities list)
void EntityComponentManager::DestroyAllEntities(void)
void EntityComponentManager::DestroyAllEntities()
{
// Mark all active entities as pending destruction. I do this because if I just destroyed
// ActiveEntities, then EntitiesPendingDestruction could have entities which have already been
@ -110,4 +112,5 @@ void EntityComponentManager::DestroyAllEntities(void)
ActiveEntities.clear(); // this should be empty anyways
EntitiesPendingDestruction.clear();
}
}

12
src/entityComponentSystem/EntityComponentManager.hpp

@ -1,11 +1,12 @@
#ifndef ENTITYCOMPONENTMANAGER_H__
#define ENTITYCOMPONENTMANAGER_H__
#pragma once
#include <map>
#include "EntityTypes.hpp"
#include "ComponentManager.hpp"
namespace gv
{
/* --EntityComponentManager--
EntityComponentManager is intended to be a very minimal managing class for the Entity Component
System. Its primary task is to facilitate the creation and destruction of Entities.
@ -61,11 +62,10 @@ public:
// Destroy all entities which have been marked for destruction. Because an entity is just an ID
// and a collection of components, this function must notify all ComponentManagers that the
// Entity should be unsubscribed from their services.
void DestroyEntitiesPendingDestruction(void);
void DestroyEntitiesPendingDestruction();
// Destroys all entities that were created by this EntityComponentManager (i.e. all entities in
// the ActiveEntities list)
void DestroyAllEntities(void);
void DestroyAllEntities();
};
#endif /* end of include guard: ENTITYCOMPONENTMANAGER_H__ */
};

6
src/entityComponentSystem/EntityTypes.cpp

@ -2,6 +2,8 @@
#include "EntityTypes.hpp"
namespace gv
{
const Entity NullEntity = 0;
bool EntityComparator(Entity a, Entity b)
@ -11,7 +13,7 @@ bool EntityComparator(Entity a, Entity b)
void EntityListAppendList(EntityList& list, const EntityList& listToAdd)
{
list.insert(list.begin(), listToAdd.begin(), listToAdd.end());
list.insert(list.end(), listToAdd.begin(), listToAdd.end());
}
void EntityListSort(EntityList& list)
@ -102,4 +104,6 @@ bool EntityListFindEntity(EntityList& list, Entity entity)
return true;
}
return false;
}
}

7
src/entityComponentSystem/EntityTypes.hpp

@ -1,8 +1,9 @@
#ifndef ENTITYTYPES_H__
#define ENTITYTYPES_H__
#pragma once
#include <vector>
namespace gv
{
// An Entity is nothing but an ID. This ID is used to get components from ComponentManagers which
// are assigned to the respective entity. Collections of components which are assigned to the same
// Entity provide the entity's data and behaviors.
@ -33,4 +34,4 @@ bool EntityListFindEntity(EntityList& list, Entity entity);
// This should probably become an enum at some point.
typedef unsigned int ComponentType;
#endif /* end of include guard: ENTITYTYPES_H__ */
};

33
src/entityComponentSystem/PooledComponentManager.hpp

@ -1,5 +1,4 @@
#ifndef POOLEDCOMPONENTMANAGER_H__
#define POOLEDCOMPONENTMANAGER_H__
#pragma once
// TODO: Handle full pool better (will be done when FragmentedPool is replaced)
#include <cassert>
@ -10,6 +9,8 @@
#include "EntityTypes.hpp"
#include "ComponentManager.hpp"
namespace gv
{
/* --PooledComponentManager--
PooledComponentManager is a general purpose PooledComponentManager that assumes you're managing your
components in a standard way.
@ -58,7 +59,7 @@ private:
EntityList Subscribers;
// TODO: Replace FragmentedPool with a better pool
FragmentedPool<PooledComponent<T> > PooledComponents;
FragmentedPool<PooledComponent<T>> PooledComponents;
protected:
typedef int FragmentedPoolIterator;
@ -69,7 +70,7 @@ protected:
{
for (int i = 0; i < PooledComponents.GetPoolSize(); i++)
{
FragmentedPoolData<PooledComponent<T> >* currentPooledComponent =
FragmentedPoolData<PooledComponent<T>>* currentPooledComponent =
PooledComponents.GetActiveDataAtIndex(i);
if (currentPooledComponent)
@ -90,7 +91,7 @@ protected:
it++;
for (; it < PooledComponents.GetPoolSize(); it++)
{
FragmentedPoolData<PooledComponent<T> >* currentPooledComponent =
FragmentedPoolData<PooledComponent<T>>* currentPooledComponent =
PooledComponents.GetActiveDataAtIndex(it);
if (currentPooledComponent)
@ -103,7 +104,7 @@ protected:
PooledComponent<T>* GetComponent(FragmentedPoolIterator& it)
{
FragmentedPoolData<PooledComponent<T> >* pooledComponent =
FragmentedPoolData<PooledComponent<T>>* pooledComponent =
PooledComponents.GetActiveDataAtIndex(it);
if (pooledComponent)
return &pooledComponent->data;
@ -112,12 +113,14 @@ protected:
// Do whatever your custom manager does for subscribing here.
// The components are already in the pool.
// It is safe to subscribe and unsubscribe components in this function
virtual void SubscribeEntitiesInternal(std::vector<PooledComponent<T>*>& components)
{
}
// Do whatever your custom manager does for unsubscribing here.
// The components are still in the subscription list and pool
// It is safe to subscribe and unsubscribe components in this function
virtual void UnsubscribeEntitiesInternal(std::vector<PooledComponent<T>*>& components)
{
}
@ -133,11 +136,11 @@ public:
}
// If the entity is already subscribed, the input component will be tossed out
void SubscribeEntities(const std::vector<PooledComponent<T> >& components)
void SubscribeEntities(const std::vector<PooledComponent<T>>& components)
{
std::vector<PooledComponent<T>*> newSubscribers(components.size());
for (typename std::vector<PooledComponent<T> >::const_iterator it = components.begin();
for (typename std::vector<PooledComponent<T>>::const_iterator it = components.begin();
it != components.end(); ++it)
{
const PooledComponent<T> currentPooledComponent = (*it);
@ -146,7 +149,7 @@ public:
if (EntityListFindEntity(Subscribers, currentPooledComponent.entity))
continue;
FragmentedPoolData<PooledComponent<T> >* newPooledComponent =
FragmentedPoolData<PooledComponent<T>>* newPooledComponent =
PooledComponents.GetNewData();
// Pool is full!
@ -182,7 +185,7 @@ public:
for (int i = 0; i < PooledComponents.GetPoolSize(); i++)
{
FragmentedPoolData<PooledComponent<T> >* currentPooledComponent =
FragmentedPoolData<PooledComponent<T>>* currentPooledComponent =
PooledComponents.GetActiveDataAtIndex(i);
if (currentPooledComponent && currentPooledComponent->data.entity == currentEntity)
@ -191,6 +194,9 @@ public:
}
// Let child do whatever it needs to unsubscribe the given entities
// Note that the child can actually unsubscribe entities in their function. This will
// currently only mean we might try to double-unsubscribe in the code below, which is not
// bad
UnsubscribeEntitiesInternal(unsubscribers);
// Remove the entities from pool (freeing memory)
@ -201,7 +207,7 @@ public:
for (int i = 0; i < PooledComponents.GetPoolSize(); i++)
{
FragmentedPoolData<PooledComponent<T> >* currentPooledComponent =
FragmentedPoolData<PooledComponent<T>>* currentPooledComponent =
PooledComponents.GetActiveDataAtIndex(i);
if (currentPooledComponent && currentPooledComponent->data.entity == currentEntity)
@ -213,11 +219,10 @@ public:
EntityListRemoveNonUniqueEntitiesInSuspect(entitiesToUnsubscribe, Subscribers);
}
void Reset(void)
void Reset()
{
PooledComponents.Clear();
Subscribers.clear();
}
};
#endif /* end of include guard: POOLEDCOMPONENTMANAGER_H__ */
}

2
src/experiments/flatbuffers/testFlatbuffers_WriteOut.cpp

@ -60,7 +60,7 @@ char *readBinary(const char *filename)
return nullptr;
}
void testFlatbufferToJSON(void)
void testFlatbufferToJSON()
{
const char *outputFilename = "Output.json";
const char *flatbufferFilename = "SavedHelloForWrite.bin";

5
src/game/Jamfile

@ -0,0 +1,5 @@
SubDir . src game ;
Library libGalaGame : agent/PlanComponentManager.cpp ;
MakeLocate libGalaGame.a : lib ;

80
src/game/agent/PlanComponentManager.cpp

@ -0,0 +1,80 @@
#include "PlanComponentManager.hpp"
#include "../../entityComponentSystem/PooledComponentManager.hpp"
PlanComponentManager::PlanComponentManager() : gv::PooledComponentManager<PlanComponentData>(100)
{
}
PlanComponentManager::~PlanComponentManager()
{
}
void PlanComponentManager::Initialize()
{
}
void PlanComponentManager::Update(float deltaSeconds)
{
// TODO: Adding true iterator support to pool will drastically help damning this to hell
gv::PooledComponentManager<PlanComponentData>::FragmentedPoolIterator it =
gv::PooledComponentManager<PlanComponentData>::NULL_POOL_ITERATOR;
for (gv::PooledComponent<PlanComponentData>* currentComponent = ActivePoolBegin(it);
currentComponent != nullptr &&
it != gv::PooledComponentManager<PlanComponentData>::NULL_POOL_ITERATOR;
currentComponent = GetNextActivePooledComponent(it))
{
if (!currentComponent)
continue;
Htn::Planner& componentPlanner = currentComponent->data.Planner;
// For now, don't follow plan, just ignore finished/failed plans
if (!componentPlanner.IsPlanRunning())
continue;
Htn::Planner::Status status = componentPlanner.PlanStep();
if (!componentPlanner.IsPlanRunning())
{
if (status == Htn::Planner::Status::PlanComplete)
{
std::cout << "PlanComponentManager: Sucessful plan for Entity "
<< currentComponent->entity << "! Final Call List:\n";
Htn::PrintTaskCallList(componentPlanner.FinalCallList);
}
if (status < Htn::Planner::Status::Running_EnumBegin)
{
std::cout << "PlanComponentManager: Failed plan for Entity "
<< currentComponent->entity << "! Initial Call List:\n";
Htn::PrintTaskCallList(componentPlanner.InitialCallList);
}
}
}
}
void PlanComponentManager::SubscribeEntitiesInternal(PlanComponentRefList& components)
{
for (gv::PooledComponent<PlanComponentData>* currentComponent : components)
{
if (!currentComponent)
continue;
Htn::Planner& planner = currentComponent->data.Planner;
Htn::TaskCallList& goalCallList = currentComponent->data.Goals;
planner.InitialCallList.insert(planner.InitialCallList.end(), goalCallList.begin(),
goalCallList.end());
}
}
void PlanComponentManager::UnsubscribeEntitiesInternal(PlanComponentRefList& components)
{
for (gv::PooledComponent<PlanComponentData>* currentComponent : components)
{
if (!currentComponent)
continue;
// Perform unsubscription
}
}

39
src/game/agent/PlanComponentManager.hpp

@ -0,0 +1,39 @@
#pragma once
#include "../../entityComponentSystem/PooledComponentManager.hpp"
#include "../../ai/htn/HTNPlanner.cpp"
#include "../../ai/WorldState.hpp"
struct PlanComponentData
{
gv::WorldState state;
Htn::TaskCallList Goals;
protected:
friend class PlanComponentManager;
Htn::Planner Planner;
};
/* --PlanComponentManager--
Prepare, manage, and execute plan(s) for Entities.
TODO: PooledComponentManager is going to need to be discarded in order to handle Entities with many
plans.
*/
class PlanComponentManager : public gv::PooledComponentManager<PlanComponentData>
{
protected:
typedef std::vector<gv::PooledComponent<PlanComponentData>*> PlanComponentRefList;
virtual void SubscribeEntitiesInternal(PlanComponentRefList& components);
virtual void UnsubscribeEntitiesInternal(PlanComponentRefList& components);
public:
typedef std::vector<gv::PooledComponent<PlanComponentData>> PlanComponentList;
PlanComponentManager();
virtual ~PlanComponentManager();
void Initialize();
virtual void Update(float deltaSeconds);
};

10
src/unitTesting/EntityComponentSystem_test.cpp

@ -6,7 +6,9 @@
#include "../entityComponentSystem/ComponentManager.hpp"
#include "../entityComponentSystem/PooledComponentManager.hpp"
void TestEntityLists(void)
using namespace gv;
void TestEntityLists()
{
EntityList testList = {1, 4, 2, 6, 3, 2, 1244};
@ -22,7 +24,7 @@ void TestEntityLists(void)
std::cout << "Done\n\n";
}
void TestEntityCreationAndDestruction(void)
void TestEntityCreationAndDestruction()
{
class TestComponentManager : public ComponentManager
{
@ -30,7 +32,7 @@ void TestEntityCreationAndDestruction(void)
EntityList Subscribers;
public:
TestComponentManager(void)
TestComponentManager()
{
Type = 1;
}
@ -149,7 +151,7 @@ void TestEntityCreationAndDestruction(void)
std::cout << "Done\n\n";
}
void TestEntityComponentTypes(void)
void TestEntityComponentTypes()
{
struct TestComponent
{

28
src/unitTesting/HTN_test.cpp

@ -10,8 +10,8 @@
class AlwaysFailPrimitiveTask : public Htn::PrimitiveTask
{
public:
AlwaysFailPrimitiveTask(void) = default;
virtual ~AlwaysFailPrimitiveTask(void) = default;
AlwaysFailPrimitiveTask() = default;
virtual ~AlwaysFailPrimitiveTask() = default;
virtual bool StateMeetsPreconditions(const Htn::WorldState& state,
const Htn::ParameterList& parameters) const
@ -35,8 +35,8 @@ public:
class RequiresStatePrimitiveTask : public Htn::PrimitiveTask
{
public:
RequiresStatePrimitiveTask(void) = default;
virtual ~RequiresStatePrimitiveTask(void) = default;
RequiresStatePrimitiveTask() = default;
virtual ~RequiresStatePrimitiveTask() = default;
virtual bool StateMeetsPreconditions(const Htn::WorldState& state,
const Htn::ParameterList& parameters) const
@ -61,8 +61,8 @@ public:
class TestPrimitiveTask : public Htn::PrimitiveTask
{
public:
TestPrimitiveTask(void) = default;
virtual ~TestPrimitiveTask(void) = default;
TestPrimitiveTask() = default;
virtual ~TestPrimitiveTask() = default;
virtual bool StateMeetsPreconditions(const Htn::WorldState& state,
const Htn::ParameterList& parameters) const
@ -87,9 +87,9 @@ public:
class TestCompoundTaskA : public Htn::CompoundTask
{
public:
TestCompoundTaskA(void) = default;
TestCompoundTaskA() = default;
virtual ~TestCompoundTaskA(void) = default;
virtual ~TestCompoundTaskA() = default;
virtual bool StateMeetsPreconditions(const Htn::WorldState& state,
const Htn::ParameterList& parameters) const
@ -186,7 +186,7 @@ TEST_CASE("Hierarchical Task Networks Planner")
REQUIRE(status == Htn::Planner::Status::PlanComplete);
REQUIRE(testPlan.FinalCallList.size() == 1);
std::cout << "\n\nFinal Plan length: " << testPlan.FinalCallList.size() << "\n";
printTaskCallList(testPlan.FinalCallList);
PrintTaskCallList(testPlan.FinalCallList);
std::cout << "\n\n";
}
@ -209,7 +209,7 @@ TEST_CASE("Hierarchical Task Networks Planner")
REQUIRE(status == Htn::Planner::Status::PlanComplete);
REQUIRE(testPlan.FinalCallList.size() == 2);
std::cout << "\n\nFinal Plan length: " << testPlan.FinalCallList.size() << "\n";
printTaskCallList(testPlan.FinalCallList);
PrintTaskCallList(testPlan.FinalCallList);
std::cout << "\n\n";
}
@ -239,7 +239,7 @@ TEST_CASE("Hierarchical Task Networks Planner")
REQUIRE(status == Htn::Planner::Status::PlanComplete);
REQUIRE(testPlan.FinalCallList.size() == 1);
std::cout << "\n\nFinal Plan length: " << testPlan.FinalCallList.size() << "\n";
printTaskCallList(testPlan.FinalCallList);
PrintTaskCallList(testPlan.FinalCallList);
std::cout << "\n\n";
}
@ -264,7 +264,7 @@ TEST_CASE("Hierarchical Task Networks Planner")
REQUIRE(status == Htn::Planner::Status::PlanComplete);
REQUIRE(testPlan.FinalCallList.size() == 2);
std::cout << "\n\nFinal Plan length: " << testPlan.FinalCallList.size() << "\n";
printTaskCallList(testPlan.FinalCallList);
PrintTaskCallList(testPlan.FinalCallList);
std::cout << "\n\n";
}
@ -292,7 +292,7 @@ TEST_CASE("Hierarchical Task Networks Planner")
REQUIRE(status == Htn::Planner::Status::Failed_NoPossiblePlan);
REQUIRE(testPlan.FinalCallList.size() == 0);
std::cout << "\n\nFinal Plan length: " << testPlan.FinalCallList.size() << "\n";
printTaskCallList(testPlan.FinalCallList);
PrintTaskCallList(testPlan.FinalCallList);
std::cout << "\n\n";
}
@ -325,7 +325,7 @@ TEST_CASE("Hierarchical Task Networks Planner")
REQUIRE(testPlan.FinalCallList.size() == 2);
REQUIRE(numIterations == 1);
std::cout << "\n\nFinal Plan length: " << testPlan.FinalCallList.size() << "\n";
printTaskCallList(testPlan.FinalCallList);
PrintTaskCallList(testPlan.FinalCallList);
std::cout << "\n\n";
}
}

11
src/util/FragmentedPool.hpp

@ -5,6 +5,7 @@
#include <iostream>
// This is some old code copied from the Horizon iteration. It's due for a rewrite.
// TODO: Add standard iterator syntax (See ObjectPool.hpp)
/* --FragmentedPool--
* FragmentedPool holds any data. It initializes the requested amount of data on construction.
@ -43,11 +44,11 @@ template <class R>
class FragmentedPool
{
private:
std::vector<FragmentedPoolData<R> > pool; // The pool data, stored in a STL vector
FragmentedPoolData<R>* firstFreeData; // The head of the free data linked list
FragmentedPoolData<R>* firstUsedData; // The head of the used data linked list
unsigned int size; // The size of the pool
unsigned int totalActiveData; // The number of active data in the pool
std::vector<FragmentedPoolData<R>> pool; // The pool data itself
FragmentedPoolData<R>* firstFreeData; // The head of the free data linked list
FragmentedPoolData<R>* firstUsedData; // The head of the used data linked list
unsigned int size; // The size of the pool
unsigned int totalActiveData; // The number of active data in the pool
// Prepare the data pointers as a linked list
void ResetPool()

10
src/util/ObjectPool.hpp

@ -39,12 +39,12 @@ public:
NextFreeData = 0;
}
typename PoolContainer<T>::iterator begin(void)
typename PoolContainer<T>::iterator begin()
{
return Pool.begin();
}
typename PoolContainer<T>::iterator end(void)
typename PoolContainer<T>::iterator end()
{
// Only return the range of data which are actually active in the pool
return Pool.begin() + NextFreeData;
@ -55,19 +55,19 @@ public:
return 0; // TODO
}
unsigned int GetSize(void)
unsigned int GetSize()
{
return Pool.size();
}
unsigned int GetNumActiveElements(void)
unsigned int GetNumActiveElements()
{
// Because NextFreeData is the index of the free data nearest to the last active data, it is
// equivalent to the number of active data
return NextFreeData;
}
T* GetNewData(void)
T* GetNewData()
{
T* newData = GetUnsafe(NextFreeData);
NextFreeData++;

Loading…
Cancel
Save