Browse Source

Fix ComponentManagers, Agent struct refactoring

- Removed PLog from Jamrules global headers
- Tagged some TODOs for easier categorization 
- Undid the static initialization auto-registering of ComponentManagers. It was causing issues when UnrealComponentManager wasn't being added to the list. This could be because of the static library, or Unreal's hotreloading. Either way, they now must be manually added like before
- Agents now use AgentConsciousState values for managing death instead of a separate bool. NeedLevelTriggers can set this state
- Various Agent-related structs now have default initialization values. Zero-initialization doesn't happen by default!
- Sublime Project now has build system for fixing "Game Module Could Not Be Loaded" Unreal Engine error message after compiling the engine
- Fixed tests which had outdated APIs; removed dead functions from Logging.hpp
combatComponentRefactor
Macoy Madson 6 years ago
parent
commit
aef82766fd
  1. 2
      Jamrules
  2. 4
      Notes.md
  3. 23
      TODO.txt
  4. 8
      src/ai/htn/HTNPlanner.cpp
  5. 3
      src/entityComponentSystem/ComponentManager.cpp
  6. 4
      src/entityComponentSystem/ComponentManager.hpp
  7. 8
      src/entityComponentSystem/EntityComponentManager.cpp
  8. 8
      src/entityComponentSystem/EntityComponentManager.hpp
  9. 4
      src/entityComponentSystem/EntitySharedData.cpp
  10. 2
      src/entityComponentSystem/EntityTypes.hpp
  11. 2
      src/game/InteractComponentManager.cpp
  12. 33
      src/game/agent/AgentComponentManager.cpp
  13. 23
      src/game/agent/AgentComponentManager.hpp
  14. 31
      src/game/agent/Needs.hpp
  15. 5
      src/game/agent/combat/CombatComponentManager.cpp
  16. 2
      src/game/agent/combat/CombatComponentManager.hpp
  17. 6
      src/project/galavantSublime/galavant.sublime-project
  18. 4
      src/unitTesting/EntityComponentSystem_test.cpp
  19. 2
      src/unitTesting/HTN_test.cpp
  20. 5
      src/util/Logging.hpp

2
Jamrules

@ -62,7 +62,7 @@ else
OPTIM = -O0 ;
HDRS = thirdParty/flatbuffers/include thirdParty/plog/include src ;
HDRS = thirdParty/flatbuffers/include src ;
# TODO: add project-specific filetype rules for things like flatbuffer .json compilation (see "UserObject rule":
# https://swarm.workshop.perforce.com/view/guest/perforce_software/jam/src/Jamfile.html ) ?

4
Notes.md

@ -6,9 +6,13 @@ Miscellaneous notes regarding working on Galavant, the code, and other random sh
- When making changes to Galavant's libraries, simply touch a GalavantUnreal source file to ensure
you get the latest Galavant changes when using Unreal's hot reloading
- After rebuilding Unreal, you may need to delete GalavantUnreal/Binaries/* if you get 'Game Module Could Not Be Loaded' error on startup
- Even if you `make` the project, you'll still need to hit the Compile button in the editor to get Unreal to compile and hotreload your code
- I added a hack which makes the engine auto scale to my desired DPI settings. You'll probably want to change these to fit your preferences. Change the value of `FSlateApplication::Get().SetApplicationScale(1.53f)` in `AGalavantUnrealMain::AGalavantUnrealMain()` to your desired DPI (1.f is the engine default).
## Comment Tags
- TODO: Something needs to get done. I use TodoReview for Sublime to find all of these easily.
- @Performance: Not justifiable as a TODO, but could be looked at when thinking about performance
- @Purity: Look into changing the code for code purity/cleanliness' sake
- @Callback: The marked function is used as a callback. Preferably @Callback [Callback type name]

23
TODO.txt

@ -53,24 +53,35 @@ Combat System
Goal #2: Minecraft but with strategy (this can be the stopping point for now)
Goal #3: Something closer to Chivalry instead of Minecraft
Seemed to see multiple actors spawned for a single berry
Massive convenience feature: Fuck, totally forgot as I was writing this. Fuck!
Was it Entity Actor integration?
Add player HUD UI - Only needs Minimap, Need bars
Actually important: Put Entity integration into AActor!
Save Jamfile documentation to repository
Cereal integration
Fix debug text over AgentCharacter for combat test
------------------
Doing
------------------
Spawning very, very broken
Seemed to see multiple actors spawned for a single berry
Actor cloning issue; see ActorEntityLifetimeManagement error. Walk back and forth to
spawn/despawn entities
Actually important: Put Entity integration into AActor!
Finish lifetime management
Only call ActorOnDestroy if it wasn't previously marked for destruction (in Actor.h)
Combat
Agent goals are broken after refactor
Segfault every time you replay in editor on scene component thing
May be fixed by actually hooking in HTNPlan to FindFood goal def (update: not fixed)
Remember to put Galavant-specific UE code into a patch or something
@ -78,6 +89,10 @@ Remember to put Galavant-specific UE code into a patch or something
Done
------------------
Spawning very, very broken
Segfault every time you replay in editor on scene component thing
Oh god, now too many things spawned! Forgot to add new AActor pointers to tracking...
Sublime "syntax" tag for build systems
Test PlanComponent event stuff

8
src/ai/htn/HTNPlanner.cpp

@ -216,7 +216,7 @@ Planner::Status Planner::PlanStep_StackFrame()
LOGD_IF(DebugPrint) << "Goal";
GoalTask* goalTask = currentTask->GetGoal();
// TODO erase ahead of time because fuck
// TODO: erase ahead of time because fuck
// Strange things are afoot when we push to stack
currentStackFrame.CallList.erase(currentTaskCallIter);
@ -379,9 +379,9 @@ Planner::Status Planner::PlanStep_StackFrame()
return Status::PlanComplete;
}
// 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
// TODO: @Performance Pool various task lists?
// TODO: @Purity Put shared code from BottomLevel/StackFrame into shared functions. It's bad that
// whenever I make a change to something I have to change it in two places
Planner::Status Planner::PlanStep()
{
Status status = Status::Failed_NoPossiblePlan;

3
src/entityComponentSystem/ComponentManager.cpp

@ -6,17 +6,14 @@ namespace gv
{
ComponentManager::ComponentManager()
{
EntityComponentManager::AddComponentManager(this);
}
ComponentManager::ComponentManager(const char* debugName) : DebugName(debugName)
{
EntityComponentManager::AddComponentManager(this);
}
ComponentManager::~ComponentManager()
{
EntityComponentManager::RemoveComponentManager(this);
}
void ComponentManager::UnsubscribeEntitiesInternal(const EntityList& entities)

4
src/entityComponentSystem/ComponentManager.hpp

@ -11,13 +11,13 @@ namespace gv
class ComponentManager
{
protected:
const char* DebugName;
EntityList Subscribers;
virtual void UnsubscribeEntitiesInternal(const EntityList& entities);
public:
const char* DebugName;
ComponentManager();
ComponentManager(const char* debugName);
virtual ~ComponentManager();

8
src/entityComponentSystem/EntityComponentManager.cpp

@ -7,7 +7,6 @@
namespace gv
{
Entity EntityComponentManager::NextNewEntity = 1;
ComponentManagerList EntityComponentManager::ComponentManagers;
EntityComponentManager g_EntityComponentManager;
EntityComponentManager::EntityComponentManager()
@ -29,7 +28,8 @@ void EntityComponentManager::AddComponentManager(ComponentManager *manager)
void EntityComponentManager::RemoveComponentManager(ComponentManager *manager)
{
for (ComponentManagerListIterator it = ComponentManagers.begin(); it != ComponentManagers.end();)
for (ComponentManagerListIterator it = ComponentManagers.begin();
it != ComponentManagers.end();)
{
if ((*it) == manager)
{
@ -52,7 +52,7 @@ void EntityComponentManager::GetNewEntities(EntityList &list, int count)
// Mark an Entity for destruction. It is not destroyed immediately; rather, it is destroyed when
// DestroyEntitiesPendingDestruction() is called.
void EntityComponentManager::MarkDestroyEntities(EntityList &entities)
void EntityComponentManager::MarkDestroyEntities(const EntityList &entities)
{
EntitiesPendingDestruction.insert(EntitiesPendingDestruction.end(), entities.begin(),
entities.end());
@ -65,6 +65,8 @@ void EntityComponentManager::UnsubscribeEntitiesFromAllManagers(EntityList &enti
// that's fine
for (ComponentManager *currentComponentManager : ComponentManagers)
{
LOGD << "Destroying " << entitiesToUnsubscribe.size() << " entities from "
<< currentComponentManager->DebugName << " (they might not all be subscribed)";
currentComponentManager->UnsubscribeEntities(entitiesToUnsubscribe);
}
}

8
src/entityComponentSystem/EntityComponentManager.hpp

@ -25,7 +25,7 @@ class EntityComponentManager
private:
typedef ComponentManagerList::iterator ComponentManagerListIterator;
static ComponentManagerList ComponentManagers;
ComponentManagerList ComponentManagers;
EntityList ActiveEntities;
EntityList EntitiesPendingDestruction;
@ -42,8 +42,8 @@ public:
EntityComponentManager();
~EntityComponentManager();
static void AddComponentManager(ComponentManager *manager);
static void RemoveComponentManager(ComponentManager *manager);
void AddComponentManager(ComponentManager *manager);
void RemoveComponentManager(ComponentManager *manager);
// Creates the given number of entities, adds them to the ActiveEntities list, and appends them
// to the provided list
@ -51,7 +51,7 @@ public:
// Mark Entities for destruction. They are not destroyed immediately; rather, they is destroyed
// when DestroyEntitiesPendingDestruction() is called.
void MarkDestroyEntities(EntityList &entities);
void MarkDestroyEntities(const EntityList &entities);
// 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

4
src/entityComponentSystem/EntitySharedData.cpp

@ -51,8 +51,8 @@ void EntityCreatePositions(const EntityList& entities, PositionRefList& position
void EntityDestroyPositions(const EntityList& entities)
{
// TODO: This is a bit bad: loop through all positions for each entity to remove approaches N
// squared
// TODO: @Performance This is a bit bad: loop through all positions for each entity to remove
// approaches N squared
for (EntityPositionRefMap::iterator it = s_Data.EntityPositionRefs.begin();
it != s_Data.EntityPositionRefs.end();)
{

2
src/entityComponentSystem/EntityTypes.hpp

@ -29,6 +29,6 @@ void EntityListRemoveNonUniqueEntitiesInSuspect(const EntityList& list, EntityLi
void EntityListRemoveUniqueEntitiesInSuspect(const EntityList& list, EntityList& suspectList);
// Linear search for entity.
// TODO: Add binary search (need to figure out when to sort these lists)
// TODO: @Performance Add binary search (need to figure out when to sort these lists)
bool EntityListFindEntity(const EntityList& list, Entity entity);
};

2
src/game/InteractComponentManager.cpp

@ -79,7 +79,7 @@ bool InteractComponentManager::PickupDirect(Entity pickupEntity, Entity claimer)
Need* needPickupAffects =
g_AgentComponentManager.GetAgentNeed(claimer, pickup->AffectsNeed);
// TODO: For testing only
// TODO: For testing only; Directly contribute to need on pickup
if (needPickupAffects)
{
needPickupAffects->Level -= 100;

33
src/game/agent/AgentComponentManager.cpp

@ -118,27 +118,30 @@ void AgentComponentManager::Update(float deltaSeconds)
LOGD_IF(DebugPrint) << "Agent Entity " << currentEntity
<< " has hit need trigger for need " << need.Def->Name;
if (needLevelTrigger.DieNow)
if (needLevelTrigger.SetConsciousState != AgentConsciousState::None)
{
currentComponent->data.IsAlive = false;
currentComponent->data.ConsciousState = AgentConsciousState::Dead;
LOGD_IF(DebugPrint) << "Agent Entity " << currentEntity
<< " has died from need " << need.Def->Name;
currentComponent->data.ConsciousState = needLevelTrigger.SetConsciousState;
if (currentComponent->data.ConsciousState == AgentConsciousState::Dead)
{
currentComponent->data.IsAlive = false;
LOGD_IF(DebugPrint) << "Agent Entity " << currentEntity
<< " has died from need " << need.Def->Name;
}
}
if (needLevelTrigger.GoalDef)
{
AgentGoal newGoal{AgentGoal::GoalStatus::StartGoal,
/*NumFailureRetries=*/0, needLevelTrigger.GoalDef,
gv::WorldResourceType::None};
AgentGoal newGoal;
newGoal.Def = needLevelTrigger.GoalDef;
AddGoalIfUniqueType(goals, newGoal);
}
else if (needLevelTrigger.NeedsResource && needLevelTrigger.WorldResource)
{
AgentGoal newNeedResourceGoal{
AgentGoal::GoalStatus::StartGoal,
/*NumFailureRetries=*/0,
gv::g_AgentGoalDefDictionary.GetResource(RESKEY("GetResource")),
needLevelTrigger.WorldResource};
AgentGoal newNeedResourceGoal;
newNeedResourceGoal.Def =
gv::g_AgentGoalDefDictionary.GetResource(RESKEY("GetResource"));
newNeedResourceGoal.WorldResource = needLevelTrigger.WorldResource;
AddGoalIfUniqueType(goals, newNeedResourceGoal);
}
}
@ -160,6 +163,10 @@ void AgentComponentManager::Update(float deltaSeconds)
{
if (goal.Def->Type == AgentGoalDef::GoalType::HtnPlan)
{
// TODO: @Purity Move validation to somewhere cleaner
if (goal.Def->Tasks.empty())
LOGE << "AgentGoalDef marked as a plan but has no Tasks!";
gv::PooledComponent<PlanComponentData> newPlanComponent;
newPlanComponent.entity = currentEntity;
newPlanComponent.data.Tasks.insert(newPlanComponent.data.Tasks.end(),

23
src/game/agent/AgentComponentManager.hpp

@ -19,31 +19,16 @@ struct AgentGoal
Failed,
Succeeded
};
GoalStatus Status;
GoalStatus Status = GoalStatus::None;
int NumFailureRetries;
int NumFailureRetries = 0;
AgentGoalDef* Def;
AgentGoalDef* Def = nullptr;
WorldResourceType WorldResource;
WorldResourceType WorldResource = WorldResourceType::None;
};
typedef std::vector<AgentGoal> AgentGoalList;
// An agent can only be one of these at a time
enum class AgentConsciousState
{
None = 0,
Conscious,
Unconscious,
Sleeping,
Dead,
AgentState_count
};
typedef std::vector<AgentConsciousState> AgentConsciousStateList;
struct AgentComponentData
{
bool IsAlive = true;

31
src/game/agent/Needs.hpp

@ -22,10 +22,10 @@ struct AgentGoalDef
GoalType_Count
};
GoalType Type;
GoalType Type = GoalType::None;
// TODO: Some sort of waiting period might be a good idea
int NumRetriesIfFailed;
int NumRetriesIfFailed = 0;
//
// Plan to achieve goal
@ -35,6 +35,21 @@ struct AgentGoalDef
extern ResourceDictionary<AgentGoalDef> g_AgentGoalDefDictionary;
// An agent can only be one of these at a time
enum class AgentConsciousState
{
None = 0,
Conscious,
Unconscious,
Sleeping,
Dead,
AgentState_count
};
typedef std::vector<AgentConsciousState> AgentConsciousStateList;
struct Need;
struct NeedLevelTrigger
{
@ -50,19 +65,19 @@ struct NeedLevelTrigger
LessThanLevel
};
ConditionType Condition;
ConditionType Condition = ConditionType::None;
float Level;
float Level = 0.f;
//
// Actions
//
bool NeedsResource;
WorldResourceType WorldResource;
bool NeedsResource = false;
WorldResourceType WorldResource = WorldResourceType::None;
bool DieNow;
AgentConsciousState SetConsciousState = AgentConsciousState::None;
AgentGoalDef* GoalDef;
AgentGoalDef* GoalDef = nullptr;
bool ConditionsMet(Need& need) const;
};

5
src/game/agent/combat/CombatComponentManager.cpp

@ -7,6 +7,11 @@ namespace gv
ResourceDictionary<CombatActionDef> g_CombatActionDefDictionary;
CombatComponentManager g_CombatComponentManager;
CombatComponentManager::CombatComponentManager()
{
DebugName = "CombatComponentManager";
}
void CombatComponentManager::Initialize(CombatFxHandler* fxHandler)
{
FxHandler = fxHandler;

2
src/game/agent/combat/CombatComponentManager.hpp

@ -95,7 +95,7 @@ protected:
virtual void UnsubscribeEntitiesInternal(const EntityList& entities);
public:
CombatComponentManager() = default;
CombatComponentManager();
virtual ~CombatComponentManager() = default;
void Initialize(CombatFxHandler* fxHandler);

6
src/project/galavantSublime/galavant.sublime-project

@ -83,6 +83,12 @@
"working_dir": "$project_path/../../../../galavant-unreal/GalavantUnreal"
},
{
"name": "GalavantUnreal Fix 'Game Module Could Not Be Loaded'",
"shell_cmd": "rm -r Binaries/Linux",
"working_dir": "$project_path/../../../../galavant-unreal/GalavantUnreal"
},
{
"name": "GalavantUnreal Generate Project Files",
"shell_cmd": "/home/macoy/Development/code/3rdParty/repositories/UnrealEngine/GenerateProjectFiles.sh -project=/home/macoy/Development/code/repositories/galavant-unreal/GalavantUnreal/GalavantUnreal.uproject -game -editor",

4
src/unitTesting/EntityComponentSystem_test.cpp

@ -34,7 +34,6 @@ void TestEntityCreationAndDestruction()
public:
TestComponentManager()
{
Type = ComponentType::Test;
}
virtual ~TestComponentManager()
{
@ -114,9 +113,6 @@ void TestEntityCreationAndDestruction()
std::cout << "Testing Entity Creation and Destruction...\n";
entityComponentManager.AddComponentManagerOfType(testComponentManager.GetType(),
&testComponentManager);
EntityList newEntities;
entityComponentManager.GetNewEntities(newEntities, 10);

2
src/unitTesting/HTN_test.cpp

@ -122,8 +122,6 @@ public:
TEST_CASE("Hierarchical Task Networks Planner")
{
gv::InitializeConsoleOnlyLogging();
Htn::Parameter testParam;
testParam.Type = Htn::Parameter::ParamType::Int;
testParam.IntValue = 123;

5
src/util/Logging.hpp

@ -80,11 +80,6 @@
namespace gv
{
void InitializeConsoleOnlyLogging();
// Feel free to pass in NULL to get the default log file
void InitializeFileOnlyLogging(const char* filename);
namespace Logging
{
enum class Severity

Loading…
Cancel
Save