
46 changed files with 1246 additions and 372 deletions
@ -1,39 +0,0 @@ |
|||
#include "HTNTaskDb.hpp" |
|||
|
|||
#include "../../util/Logging.hpp" |
|||
|
|||
namespace Htn |
|||
{ |
|||
namespace TaskDb |
|||
{ |
|||
typedef std::map<TaskName, Task*> TaskDb; |
|||
static TaskDb s_TaskDb; |
|||
void ClearAllTasks() |
|||
{ |
|||
s_TaskDb.clear(); |
|||
} |
|||
|
|||
void AddTask(Task* task, TaskName taskName) |
|||
{ |
|||
if (task && taskName != TaskName::None) |
|||
{ |
|||
TaskDb::iterator findIt = s_TaskDb.find(taskName); |
|||
if (findIt != s_TaskDb.end()) |
|||
LOGW << "Replacing task with name " << (int)taskName << ". If in Unreal, this is fine"; |
|||
|
|||
s_TaskDb[taskName] = task; |
|||
} |
|||
} |
|||
|
|||
Task* GetTask(TaskName taskName) |
|||
{ |
|||
if (taskName != TaskName::None) |
|||
{ |
|||
TaskDb::iterator findIt = s_TaskDb.find(taskName); |
|||
if (findIt != s_TaskDb.end()) |
|||
return findIt->second; |
|||
} |
|||
return nullptr; |
|||
} |
|||
} |
|||
} |
@ -1,30 +0,0 @@ |
|||
#pragma once |
|||
|
|||
#include "HTNTasks.hpp" |
|||
|
|||
namespace Htn |
|||
{ |
|||
enum class TaskName |
|||
{ |
|||
None = 0, |
|||
|
|||
// Goals
|
|||
|
|||
// Compounds
|
|||
GetResource, |
|||
|
|||
// Primitives
|
|||
FindResource, |
|||
MoveTo, |
|||
InteractPickup, |
|||
|
|||
TaskName_count |
|||
}; |
|||
|
|||
namespace TaskDb |
|||
{ |
|||
void ClearAllTasks(); |
|||
void AddTask(Task* task, TaskName taskName); |
|||
Task* GetTask(TaskName taskName); |
|||
} |
|||
} |
@ -1,17 +0,0 @@ |
|||
#pragma once |
|||
|
|||
namespace gv |
|||
{ |
|||
enum class ComponentType : unsigned int |
|||
{ |
|||
None = 0, |
|||
|
|||
Test, |
|||
Movement, |
|||
Agent, |
|||
Plan, |
|||
Interact, |
|||
|
|||
ComponentType_count |
|||
}; |
|||
}; |
@ -0,0 +1,5 @@ |
|||
SubDir . src frontends ; |
|||
|
|||
SubDirC++Flags $(TESTSC++FLAGS) ; |
|||
|
|||
SubInclude . src frontends consoleOnly ; |
@ -0,0 +1,147 @@ |
|||
#include "ConsoleMovementComponentManager.hpp" |
|||
|
|||
#include <algorithm> |
|||
|
|||
ConsoleMovementComponentManager g_ConsoleMovementComponentManager; |
|||
|
|||
ConsoleMovementComponentManager::ConsoleMovementComponentManager() |
|||
{ |
|||
DebugName = "ConsoleMovementComponentManager"; |
|||
} |
|||
|
|||
void ConsoleMovementComponentManager::Initialize( |
|||
gv::CallbackContainer<Htn::TaskEventCallback>* taskEventCallbacks) |
|||
{ |
|||
TaskEventCallbacks = taskEventCallbacks; |
|||
} |
|||
|
|||
void ConsoleMovementComponentManager::UnsubscribeEntitiesInternal(const gv::EntityList& entities) |
|||
{ |
|||
for (MovementComponentList::iterator it = MovementComponents.begin(); |
|||
it != MovementComponents.end();) |
|||
{ |
|||
gv::Entity currentEntity = (*it).entity; |
|||
bool foundEntity = false; |
|||
for (const gv::Entity& unsubscribeEntity : entities) |
|||
{ |
|||
if (currentEntity == unsubscribeEntity) |
|||
{ |
|||
it = MovementComponents.erase(it); |
|||
foundEntity = true; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (!foundEntity) |
|||
++it; |
|||
} |
|||
} |
|||
|
|||
void ConsoleMovementComponentManager::CreateMovementComponents( |
|||
const gv::EntityList& entities, MovementComponentRefList& newMovementComponents) |
|||
{ |
|||
// Only create MovementComponents which aren't already subscribed
|
|||
gv::EntityList entitiesToSubscribe = entities; |
|||
gv::EntityListRemoveNonUniqueEntitiesInSuspect(Subscribers, entitiesToSubscribe); |
|||
|
|||
unsigned int endBeforeResize = MovementComponents.size(); |
|||
MovementComponents.resize(MovementComponents.size() + entitiesToSubscribe.size()); |
|||
|
|||
int numEntitiesCreated = 0; |
|||
for (unsigned int i = endBeforeResize; i < MovementComponents.size(); i++) |
|||
{ |
|||
MovementComponent* newMovementComponent = &MovementComponents[i]; |
|||
newMovementComponent->entity = entitiesToSubscribe[numEntitiesCreated++]; |
|||
newMovementComponents.push_back(newMovementComponent); |
|||
} |
|||
|
|||
// We've already made sure all entities in the list are unique
|
|||
gv::EntityListAppendList(Subscribers, entitiesToSubscribe); |
|||
} |
|||
|
|||
void ConsoleMovementComponentManager::Update(float deltaSeconds) |
|||
{ |
|||
Htn::TaskEventList eventList; |
|||
gv::EntityList entitiesToUnsubscribe; |
|||
|
|||
for (MovementComponent& component : MovementComponents) |
|||
{ |
|||
gv::Position targetPosition; |
|||
|
|||
// Decide where we're going to go
|
|||
{ |
|||
if (component.GoalWorldPosition) |
|||
{ |
|||
if (component.Position.ManhattanTo(component.GoalWorldPosition) > |
|||
component.GoalManDistanceTolerance) |
|||
{ |
|||
targetPosition = component.GoalWorldPosition; |
|||
} |
|||
else |
|||
{ |
|||
component.GoalWorldPosition.Reset(); |
|||
|
|||
Htn::TaskEvent goalPositionReachedEvent{ |
|||
Htn::TaskEvent::TaskResult::TaskSucceeded, component.entity}; |
|||
eventList.push_back(goalPositionReachedEvent); |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (component.ResourceType != gv::WorldResourceType::None && |
|||
!component.ResourcePosition.Equals(component.Position, 100.f)) |
|||
{ |
|||
// Give ResourceLocator our new position
|
|||
gv::WorldResourceLocator::MoveResource(component.ResourceType, component.entity, |
|||
component.ResourcePosition, component.Position); |
|||
component.ResourcePosition = component.Position; |
|||
} |
|||
|
|||
// Perform movement
|
|||
if (targetPosition) |
|||
{ |
|||
gv::Position deltaPosition = targetPosition - component.Position; |
|||
gv::Position deltaVelocity = deltaPosition.GetSafeNormal(0.1f); |
|||
deltaVelocity.Scale(component.MaxSpeed * deltaSeconds); |
|||
// Disallow flying
|
|||
deltaVelocity[2] = 0; |
|||
|
|||
component.Position += deltaVelocity; |
|||
} |
|||
} |
|||
|
|||
if (TaskEventCallbacks && !eventList.empty()) |
|||
{ |
|||
for (gv::CallbackCall<Htn::TaskEventCallback>& callback : TaskEventCallbacks->Callbacks) |
|||
callback.Callback(eventList, callback.UserData); |
|||
} |
|||
|
|||
if (!entitiesToUnsubscribe.empty()) |
|||
UnsubscribeEntities(entitiesToUnsubscribe); |
|||
} |
|||
|
|||
// TODO: This should return whether it was actually successful (i.e. the entity exists)
|
|||
void ConsoleMovementComponentManager::PathEntitiesTo(const gv::EntityList& entities, |
|||
const gv::PositionList& positions) |
|||
{ |
|||
if (entities.empty() || entities.size() != positions.size()) |
|||
return; |
|||
|
|||
for (unsigned int i = 0; i < entities.size(); i++) |
|||
{ |
|||
const gv::Entity& entityToMove = entities[i]; |
|||
const gv::Position& targetPosition = positions[i]; |
|||
|
|||
// For now, entities which are not subscribed will be tossed out
|
|||
if (std::find(Subscribers.begin(), Subscribers.end(), entityToMove) == Subscribers.end()) |
|||
continue; |
|||
|
|||
for (MovementComponent& component : MovementComponents) |
|||
{ |
|||
if (component.entity == entityToMove) |
|||
{ |
|||
component.GoalWorldPosition = targetPosition; |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,56 @@ |
|||
#pragma once |
|||
|
|||
#include "entityComponentSystem/EntityTypes.hpp" |
|||
#include "entityComponentSystem/ComponentManager.hpp" |
|||
#include "world/Position.hpp" |
|||
#include "world/WorldResourceLocator.hpp" |
|||
#include "ai/htn/HTNTypes.hpp" |
|||
#include "game/agent/MovementManager.hpp" |
|||
#include "util/CallbackContainer.hpp" |
|||
|
|||
struct MovementComponent |
|||
{ |
|||
gv::Entity entity; |
|||
gv::Position Position; |
|||
|
|||
gv::Position GoalWorldPosition; |
|||
float GoalManDistanceTolerance = 400.f; |
|||
float MaxSpeed = 500.f; |
|||
|
|||
// If provided, this entity will be registered in the WorldResourceLocator under this type
|
|||
gv::WorldResourceType ResourceType = gv::WorldResourceType::None; |
|||
|
|||
// The last position we told the ResourceLocator we were at (used so that when we move we can
|
|||
// find the agent to move in ResourceLocator)
|
|||
gv::Position ResourcePosition; |
|||
}; |
|||
|
|||
typedef std::vector<MovementComponent> MovementComponentList; |
|||
typedef std::vector<MovementComponent*> MovementComponentRefList; |
|||
|
|||
class ConsoleMovementComponentManager : public gv::ComponentManager, public gv::MovementManager |
|||
{ |
|||
private: |
|||
gv::CallbackContainer<Htn::TaskEventCallback>* TaskEventCallbacks; |
|||
|
|||
MovementComponentList MovementComponents; |
|||
|
|||
protected: |
|||
virtual void UnsubscribeEntitiesInternal(const gv::EntityList& entities); |
|||
|
|||
public: |
|||
ConsoleMovementComponentManager(); |
|||
virtual ~ConsoleMovementComponentManager() = default; |
|||
|
|||
void Initialize(gv::CallbackContainer<Htn::TaskEventCallback>* taskEventCallbacks); |
|||
|
|||
void CreateMovementComponents(const gv::EntityList& entities, |
|||
MovementComponentRefList& newMovementComponents); |
|||
|
|||
virtual void Update(float deltaSeconds); |
|||
|
|||
// TODO: This should return whether it was actually successful (i.e. the entity exists)
|
|||
virtual void PathEntitiesTo(const gv::EntityList& entities, const gv::PositionList& positions); |
|||
}; |
|||
|
|||
extern ConsoleMovementComponentManager g_ConsoleMovementComponentManager; |
@ -0,0 +1,396 @@ |
|||
#include "util/Logging.hpp" |
|||
|
|||
#include "world/WorldResourceLocator.hpp" |
|||
#include "world/ProceduralWorld.hpp" |
|||
#include "entityComponentSystem/EntityTypes.hpp" |
|||
#include "entityComponentSystem/EntityComponentManager.hpp" |
|||
#include "game/agent/PlanComponentManager.hpp" |
|||
#include "game/agent/AgentComponentManager.hpp" |
|||
#include "game/agent/combat/CombatComponentManager.hpp" |
|||
#include "game/InteractComponentManager.hpp" |
|||
#include "game/agent/Needs.hpp" |
|||
#include "ai/htn/HTNTasks.hpp" |
|||
#include "game/agent/htnTasks/MovementTasks.hpp" |
|||
#include "game/agent/htnTasks/InteractTasks.hpp" |
|||
#include "util/CallbackContainer.hpp" |
|||
#include "game/EntityLevelOfDetail.hpp" |
|||
#include "util/StringHashing.hpp" |
|||
|
|||
#include "ConsoleMovementComponentManager.hpp" |
|||
|
|||
#include <iostream> |
|||
|
|||
#include <cstring> |
|||
#include <cstdlib> |
|||
#include <cstdio> |
|||
|
|||
// @Callback: CustomLogOutputFunc
|
|||
void ConsoleOnlyLogOutput(const gv::Logging::Record& record) |
|||
{ |
|||
bool IsWarning = (record.severity == gv::Logging::Severity::warning); |
|||
bool IsError = (record.severity <= gv::Logging::Severity::error); |
|||
|
|||
static char funcNameBuffer[256]; |
|||
gv::Logging::FormatFuncName(funcNameBuffer, record.Function, sizeof(funcNameBuffer)); |
|||
|
|||
static char buffer[2048]; |
|||
snprintf(buffer, sizeof(buffer), "%s():%lu: %s", funcNameBuffer, (unsigned long)record.Line, |
|||
record.OutBuffer); |
|||
|
|||
if (IsError) |
|||
{ |
|||
std::cout << "Error: " << buffer << "\n"; |
|||
} |
|||
else if (IsWarning) |
|||
{ |
|||
std::cout << "Warning: " << buffer << "\n"; |
|||
} |
|||
else |
|||
{ |
|||
std::cout << "Log: " << buffer << "\n"; |
|||
} |
|||
} |
|||
|
|||
static gv::Logging::Logger s_UnrealLogger(gv::Logging::Severity::debug, &ConsoleOnlyLogOutput); |
|||
|
|||
void InitializeResources() |
|||
{ |
|||
// Hunger Need
|
|||
{ |
|||
static gv::NeedDef TestHungerNeed; |
|||
TestHungerNeed.Type = gv::NeedType::Hunger; |
|||
TestHungerNeed.Name = "Hunger"; |
|||
TestHungerNeed.InitialLevel = 70.f; |
|||
TestHungerNeed.MaxLevel = 300.f; |
|||
TestHungerNeed.MinLevel = 0.f; |
|||
TestHungerNeed.UpdateRate = 10.f; |
|||
TestHungerNeed.AddPerUpdate = 10.f; |
|||
|
|||
// Find food goal def
|
|||
{ |
|||
Htn::Parameter resourceToFind; |
|||
resourceToFind.IntValue = gv::WorldResourceType::Food; |
|||
resourceToFind.Type = Htn::Parameter::ParamType::Int; |
|||
Htn::ParameterList parameters = {resourceToFind}; |
|||
Htn::TaskCall getResourceCall{Htn::g_TaskDictionary.GetResource(RESKEY("GetResource")), |
|||
parameters}; |
|||
Htn::TaskCall pickupResourceCall{ |
|||
Htn::g_TaskDictionary.GetResource(RESKEY("InteractPickup")), parameters}; |
|||
Htn::TaskCallList getResourceTasks = {getResourceCall, pickupResourceCall}; |
|||
static gv::AgentGoalDef s_findFoodGoalDef; |
|||
s_findFoodGoalDef.Type = gv::AgentGoalDef::GoalType::HtnPlan; |
|||
s_findFoodGoalDef.NumRetriesIfFailed = 2; |
|||
s_findFoodGoalDef.Tasks = getResourceTasks; |
|||
gv::g_AgentGoalDefDictionary.AddResource(RESKEY("FindFood"), &s_findFoodGoalDef); |
|||
} |
|||
|
|||
// Hunger Need Triggers
|
|||
{ |
|||
gv::NeedLevelTrigger lookForFood; |
|||
lookForFood.Condition = gv::NeedLevelTrigger::ConditionType::GreaterThanLevel; |
|||
lookForFood.Level = 100.f; |
|||
lookForFood.NeedsResource = true; |
|||
lookForFood.WorldResource = gv::WorldResourceType::Food; |
|||
TestHungerNeed.LevelTriggers.push_back(lookForFood); |
|||
|
|||
gv::NeedLevelTrigger desperateLookForFood; |
|||
desperateLookForFood.Condition = gv::NeedLevelTrigger::ConditionType::GreaterThanLevel; |
|||
desperateLookForFood.Level = 200.f; |
|||
desperateLookForFood.GoalDef = |
|||
gv::g_AgentGoalDefDictionary.GetResource(RESKEY("FindFood")); |
|||
TestHungerNeed.LevelTriggers.push_back(desperateLookForFood); |
|||
|
|||
gv::NeedLevelTrigger deathByStarvation; |
|||
deathByStarvation.Condition = gv::NeedLevelTrigger::ConditionType::GreaterThanLevel; |
|||
deathByStarvation.Level = 290.f; |
|||
deathByStarvation.SetConsciousState = gv::AgentConsciousState::Dead; |
|||
TestHungerNeed.LevelTriggers.push_back(deathByStarvation); |
|||
} |
|||
|
|||
gv::g_NeedDefDictionary.AddResource(RESKEY("Hunger"), &TestHungerNeed); |
|||
} |
|||
|
|||
// Blood Need
|
|||
{ |
|||
static gv::NeedDef BloodNeed; |
|||
BloodNeed.Type = gv::NeedType::Blood; |
|||
BloodNeed.Name = "Blood"; |
|||
BloodNeed.InitialLevel = 100.f; |
|||
BloodNeed.MaxLevel = 100.f; |
|||
BloodNeed.MinLevel = 0.f; |
|||
// Agents will only gain blood over time, but there's a maximum and they start at max
|
|||
BloodNeed.UpdateRate = 10.f; |
|||
BloodNeed.AddPerUpdate = 10.f; |
|||
|
|||
// Blood Need Triggers
|
|||
{ |
|||
gv::NeedLevelTrigger lowBloodUnconscious; |
|||
lowBloodUnconscious.Condition = gv::NeedLevelTrigger::ConditionType::LessThanLevel; |
|||
lowBloodUnconscious.Level = 20.f; |
|||
lowBloodUnconscious.SetConsciousState = gv::AgentConsciousState::Unconscious; |
|||
BloodNeed.LevelTriggers.push_back(lowBloodUnconscious); |
|||
|
|||
gv::NeedLevelTrigger deathByBleedingOut; |
|||
deathByBleedingOut.Condition = gv::NeedLevelTrigger::ConditionType::Zero; |
|||
deathByBleedingOut.SetConsciousState = gv::AgentConsciousState::Dead; |
|||
BloodNeed.LevelTriggers.push_back(deathByBleedingOut); |
|||
} |
|||
|
|||
gv::g_NeedDefDictionary.AddResource(RESKEY("Blood"), &BloodNeed); |
|||
} |
|||
|
|||
// Goals
|
|||
{ |
|||
static gv::AgentGoalDef s_getResourceGoalDef; |
|||
s_getResourceGoalDef.Type = gv::AgentGoalDef::GoalType::GetResource; |
|||
s_getResourceGoalDef.NumRetriesIfFailed = 2; |
|||
gv::g_AgentGoalDefDictionary.AddResource(RESKEY("GetResource"), &s_getResourceGoalDef); |
|||
} |
|||
|
|||
// CombatActionDefs
|
|||
{ |
|||
// Punch
|
|||
{ |
|||
static gv::CombatActionDef s_punchAction; |
|||
s_punchAction.Type = gv::CombatActionDef::CombatActionType::Attack; |
|||
s_punchAction.Duration = .75f; |
|||
s_punchAction.Damage = {RESKEY("Blood"), 10.f, 50.f}; |
|||
s_punchAction.Knockback = {1.f, 500.f}; |
|||
|
|||
gv::g_CombatActionDefDictionary.AddResource(RESKEY("Punch"), &s_punchAction); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void InitializeEntityTests() |
|||
{ |
|||
// Create a couple test entities
|
|||
int numTestEntities = 20; |
|||
gv::EntityList testEntities; |
|||
testEntities.reserve(numTestEntities); |
|||
gv::g_EntityComponentManager.GetNewEntities(testEntities, numTestEntities); |
|||
|
|||
// Add Movement components to all of them
|
|||
{ |
|||
MovementComponentRefList newMovementComponents; |
|||
newMovementComponents.reserve(numTestEntities); |
|||
g_ConsoleMovementComponentManager.CreateMovementComponents(testEntities, |
|||
newMovementComponents); |
|||
|
|||
float spacing = 500.f; |
|||
int i = 0; |
|||
for (MovementComponent* newAgentMovementComponent : newMovementComponents) |
|||
{ |
|||
newAgentMovementComponent->ResourceType = gv::WorldResourceType::Agent; |
|||
newAgentMovementComponent->Position.Set(0.f, i++ * spacing, 0.f); |
|||
newAgentMovementComponent->GoalManDistanceTolerance = 600.f; |
|||
newAgentMovementComponent->MaxSpeed = 500.f; |
|||
} |
|||
} |
|||
|
|||
// Setup agent components for all of them and give them a need
|
|||
{ |
|||
gv::Need hungerNeed(RESKEY("Hunger")); |
|||
gv::Need bloodNeed(RESKEY("Blood")); |
|||
|
|||
// TODO: Will eventually need a thing which creates agents based on a creation def and sets
|
|||
// up the needs accordingly
|
|||
|
|||
gv::AgentComponentManager::AgentComponentList newAgentComponents(numTestEntities); |
|||
|
|||
int i = 0; |
|||
for (gv::PooledComponent<gv::AgentComponentData>& currentAgentComponent : |
|||
newAgentComponents) |
|||
{ |
|||
currentAgentComponent.entity = testEntities[i++]; |
|||
currentAgentComponent.data.Needs.push_back(hungerNeed); |
|||
currentAgentComponent.data.Needs.push_back(bloodNeed); |
|||
} |
|||
|
|||
gv::g_AgentComponentManager.SubscribeEntities(newAgentComponents); |
|||
} |
|||
|
|||
// Add food
|
|||
{ |
|||
int numFood = 4; |
|||
|
|||
gv::EntityList testFoodEntities; |
|||
testFoodEntities.reserve(numFood); |
|||
gv::g_EntityComponentManager.GetNewEntities(testFoodEntities, numFood); |
|||
|
|||
MovementComponentRefList newMovementComponents; |
|||
newMovementComponents.reserve(numFood); |
|||
g_ConsoleMovementComponentManager.CreateMovementComponents(testFoodEntities, |
|||
newMovementComponents); |
|||
|
|||
gv::PickupRefList newPickups; |
|||
newPickups.reserve(numFood); |
|||
gv::g_InteractComponentManager.CreatePickups(testFoodEntities, newPickups); |
|||
|
|||
// Movement components
|
|||
float spacing = 2000.f; |
|||
int i = 0; |
|||
for (MovementComponent* newFoodMovementComponent : newMovementComponents) |
|||
{ |
|||
newFoodMovementComponent->ResourceType = gv::WorldResourceType::Food; |
|||
newFoodMovementComponent->Position.Set(-2000.f, i++ * spacing, 0.f); |
|||
// Food doesn't move
|
|||
newFoodMovementComponent->MaxSpeed = 0.f; |
|||
} |
|||
|
|||
// Pickup components
|
|||
for (gv::Pickup* newPickup : newPickups) |
|||
{ |
|||
newPickup->AffectsNeed = gv::NeedType::Hunger; |
|||
newPickup->DestroySelfOnPickup = true; |
|||
} |
|||
} |
|||
} |
|||
|
|||
void InitializeProceduralWorld() |
|||
{ |
|||
gv::ProceduralWorld::ProceduralWorldParams& Params = |
|||
gv::ProceduralWorld::GetActiveWorldParams(); |
|||
|
|||
Params.WorldCellMaxHeight = 200.f; |
|||
Params.WorldCellMinHeight = -10000.f; |
|||
|
|||
Params.Seed = 5138008; |
|||
|
|||
for (int i = 0; i < 3; i++) |
|||
Params.WorldCellTileSize[i] = 120.f; |
|||
|
|||
// Hardcoded noise values because I won't be changing these often
|
|||
Params.ScaledNoiseParams.lowBound = 0.f; |
|||
Params.ScaledNoiseParams.highBound = 255.f; |
|||
Params.ScaledNoiseParams.octaves = 10; |
|||
Params.ScaledNoiseParams.scale = 0.00001f; |
|||
Params.ScaledNoiseParams.persistence = 0.55f; |
|||
Params.ScaledNoiseParams.lacunarity = 2.f; |
|||
} |
|||
|
|||
void InitializeGalavant() |
|||
{ |
|||
LOGI << "Initializing Galavant..."; |
|||
|
|||
InitializeProceduralWorld(); |
|||
|
|||
gv::WorldResourceLocator::ClearResources(); |
|||
|
|||
// Initialize Entity Components
|
|||
{ |
|||
// I originally made this happen via static initialization, but using that in combination
|
|||
// with A) split Galavant static library and GalavantUnreal library and B) Unreal
|
|||
// Hotreloading caused issues (mainly that Unreal-specific ComponentManagers weren't being
|
|||
// registered in the same list)
|
|||
gv::g_EntityComponentManager.AddComponentManager(&gv::g_InteractComponentManager); |
|||
gv::g_EntityComponentManager.AddComponentManager(&gv::g_CombatComponentManager); |
|||
gv::g_EntityComponentManager.AddComponentManager(&gv::g_AgentComponentManager); |
|||
gv::g_EntityComponentManager.AddComponentManager(&gv::g_PlanComponentManager); |
|||
gv::g_EntityComponentManager.AddComponentManager(&g_ConsoleMovementComponentManager); |
|||
|
|||
static gv::CallbackContainer<Htn::TaskEventCallback> TaskEventCallbacks; |
|||
|
|||
g_ConsoleMovementComponentManager.Initialize(&TaskEventCallbacks); |
|||
|
|||
{ |
|||
static gv::WorldStateManager WorldStateManager; |
|||
gv::g_PlanComponentManager.Initialize(&WorldStateManager, &TaskEventCallbacks); |
|||
//gv::g_PlanComponentManager.DebugPrint = true;
|
|||
} |
|||
|
|||
{ |
|||
gv::g_AgentComponentManager.Initialize(&gv::g_PlanComponentManager); |
|||
gv::g_AgentComponentManager.DebugPrint = true; |
|||
} |
|||
|
|||
// gv::g_CombatComponentManager.Initialize(&CombatFxHandler);
|
|||
gv::g_CombatComponentManager.Initialize(nullptr); |
|||
} |
|||
|
|||
// Initialize Tasks
|
|||
{ |
|||
static gv::FindResourceTask FindResourceTask; |
|||
static gv::MoveToTask MoveToTask; |
|||
static gv::GetResourceTask GetResourceTask; |
|||
static gv::InteractPickupTask InteractPickupTask; |
|||
|
|||
MoveToTask.Initialize(&g_ConsoleMovementComponentManager); |
|||
GetResourceTask.Initialize(&FindResourceTask, &MoveToTask); |
|||
InteractPickupTask.Initialize(&gv::g_InteractComponentManager); |
|||
|
|||
Htn::g_TaskDictionary.AddResource(RESKEY("FindResource"), FindResourceTask.GetTask()); |
|||
Htn::g_TaskDictionary.AddResource(RESKEY("MoveTo"), MoveToTask.GetTask()); |
|||
Htn::g_TaskDictionary.AddResource(RESKEY("GetResource"), GetResourceTask.GetTask()); |
|||
Htn::g_TaskDictionary.AddResource(RESKEY("InteractPickup"), InteractPickupTask.GetTask()); |
|||
} |
|||
|
|||
InitializeResources(); |
|||
|
|||
// Initialize test levels
|
|||
{ |
|||
InitializeEntityTests(); |
|||
} |
|||
|
|||
// Initialize LOD settings
|
|||
{ |
|||
float PlayerManhattanViewDistance = 10000.f; |
|||
gv::EntityLOD::g_EntityLODSettings.PlayerManhattanViewDistance = |
|||
PlayerManhattanViewDistance; |
|||
} |
|||
|
|||
LOGI << "Galavant Initialized"; |
|||
} |
|||
|
|||
static float s_currentWorldTime = 0.f; |
|||
|
|||
int main() |
|||
{ |
|||
InitializeGalavant(); |
|||
|
|||
LOGI << "******* Starting main loop ********"; |
|||
|
|||
// Main loop
|
|||
float totalRuntime = 100.f; |
|||
float tickRate = 1.f; |
|||
int numTicks = 0; |
|||
for (float currentTime = 0.f; currentTime < totalRuntime; currentTime += tickRate) |
|||
{ |
|||
s_currentWorldTime = currentTime; |
|||
float deltaTime = tickRate; |
|||
|
|||
gv::g_EntityComponentManager.DestroyEntitiesPendingDestruction(); |
|||
|
|||
// GalavantMain.Update(deltaTime);
|
|||
|
|||
gv::g_CombatComponentManager.Update(deltaTime); |
|||
gv::g_AgentComponentManager.Update(deltaTime); |
|||
gv::g_PlanComponentManager.Update(deltaTime); |
|||
g_ConsoleMovementComponentManager.Update(deltaTime); |
|||
|
|||
numTicks++; |
|||
} |
|||
|
|||
LOGI << "******** Finished; cleaning up... (ticked " << numTicks << " times) ********"; |
|||
|
|||
// Cleanup
|
|||
{ |
|||
gv::g_EntityComponentManager.DestroyAllEntities(); |
|||
LOGI << "Destroyed all entities"; |
|||
gv::WorldResourceLocator::ClearResources(); |
|||
gv::ResourceDictionaryBase::ClearAllDictionaries(); |
|||
} |
|||
|
|||
LOGI << "Exiting"; |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
// Latelinked functions
|
|||
namespace gv |
|||
{ |
|||
float GetWorldTime() |
|||
{ |
|||
return s_currentWorldTime; |
|||
} |
|||
} |
@ -0,0 +1,15 @@ |
|||
SubDir . src frontends consoleOnly ; |
|||
|
|||
SubDirC++Flags $(TESTSC++FLAGS) ; |
|||
|
|||
Main consoleOnlyFrontend : ConsoleOnlyMain.cpp ConsoleMovementComponentManager.cpp ; |
|||
|
|||
LinkLibraries consoleOnlyFrontend : libGalaGame |
|||
libGalaWorld |
|||
libGalaAi |
|||
libGalaEntityComponent |
|||
libGalaThirdPartyWrapper |
|||
libGalavant |
|||
libGalaUtil ; |
|||
|
|||
MakeLocate consoleOnlyFrontend : bin ; |