Continued working on GOAP action executor
This commit is contained in:
@@ -9,7 +9,89 @@
|
||||
#include "CharacterAIModule.h"
|
||||
namespace ECS
|
||||
{
|
||||
class ActionNodeActions {
|
||||
struct ActionExec {
|
||||
struct PlanExecData {
|
||||
TownNPCs::NPCData &npc;
|
||||
Blackboard &bb;
|
||||
nlohmann::json &memory;
|
||||
};
|
||||
enum { OK = 0, BUSY, ERROR };
|
||||
TownNPCs::NPCData &npc;
|
||||
Blackboard &bb;
|
||||
nlohmann::json &memory;
|
||||
bool complete;
|
||||
bool active;
|
||||
const goap::BaseAction<Blackboard> *action;
|
||||
ActionExec(PlanExecData &data,
|
||||
const goap::BaseAction<Blackboard> *action)
|
||||
: npc(data.npc)
|
||||
, bb(data.bb)
|
||||
, memory(data.memory)
|
||||
, complete(false)
|
||||
, active(false)
|
||||
, action(action)
|
||||
{
|
||||
}
|
||||
ActionExec(const ActionExec &other)
|
||||
: npc(other.npc)
|
||||
, bb(other.bb)
|
||||
, memory(other.memory)
|
||||
, complete(other.complete)
|
||||
, active(other.active)
|
||||
, action(other.action)
|
||||
{
|
||||
}
|
||||
ActionExec &operator=(const ActionExec &other)
|
||||
{
|
||||
npc = other.npc;
|
||||
bb = other.bb;
|
||||
memory = other.memory;
|
||||
complete = other.complete;
|
||||
active = other.active;
|
||||
action = other.action;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual int update(float delta) = 0;
|
||||
virtual void finish(int result) = 0;
|
||||
virtual void activate() = 0;
|
||||
|
||||
public:
|
||||
int operator()(float delta)
|
||||
{
|
||||
if (!active)
|
||||
activate();
|
||||
int ret = update(delta);
|
||||
if (ret != BUSY)
|
||||
finish(ret);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
struct PlanExec {
|
||||
enum { OK = 0, BUSY, ERROR };
|
||||
std::vector<struct ActionExec *> action_exec;
|
||||
int index;
|
||||
PlanExec()
|
||||
: index(-1)
|
||||
{
|
||||
}
|
||||
int operator()(float delta)
|
||||
{
|
||||
if (index == -1)
|
||||
index = 0;
|
||||
int rc = (*action_exec[index])(delta);
|
||||
if (rc == ActionExec::ERROR)
|
||||
return ERROR;
|
||||
if (action_exec[index]->complete)
|
||||
index++;
|
||||
if (index >= action_exec.size())
|
||||
return OK;
|
||||
return BUSY;
|
||||
}
|
||||
};
|
||||
|
||||
struct ActionNodeActions {
|
||||
struct WalkToAction : public goap::BaseAction<Blackboard> {
|
||||
int node;
|
||||
WalkToAction(int node, int cost)
|
||||
@@ -98,12 +180,103 @@ out:
|
||||
std::vector<goap::BaseAction<Blackboard> *> m_actions;
|
||||
|
||||
public:
|
||||
struct ActionExecWalk : ActionExec {
|
||||
private:
|
||||
Ogre::Vector3 targetPosition;
|
||||
float radius;
|
||||
int update(float delta) override
|
||||
{
|
||||
if (npc.e.is_valid()) {
|
||||
Ogre::Vector3 position =
|
||||
npc.e.get<CharacterBase>()
|
||||
.mBodyNode
|
||||
->_getDerivedPosition();
|
||||
if (position.squaredDistance(targetPosition) >=
|
||||
radius * radius) {
|
||||
if (npc.e.is_valid())
|
||||
npc.e.get<CharacterBase>()
|
||||
.mBodyNode
|
||||
->_setDerivedPosition(
|
||||
targetPosition);
|
||||
npc.position = targetPosition;
|
||||
return BUSY;
|
||||
}
|
||||
} else {
|
||||
if (npc.position.squaredDistance(
|
||||
targetPosition) >=
|
||||
radius * radius) {
|
||||
npc.position = targetPosition;
|
||||
return BUSY;
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
void finish(int rc) override
|
||||
{
|
||||
if (rc == OK)
|
||||
bb.apply(action->effects);
|
||||
}
|
||||
void activate() override
|
||||
{
|
||||
const ActionNodeActions::WalkToAction *wtaction =
|
||||
static_cast<
|
||||
const ActionNodeActions::WalkToAction *>(
|
||||
action);
|
||||
radius = ECS::get<ActionNodeList>()
|
||||
.dynamicNodes[wtaction->node]
|
||||
.radius;
|
||||
targetPosition = ECS::get<ActionNodeList>()
|
||||
.dynamicNodes[wtaction->node]
|
||||
.position;
|
||||
Ogre::Vector3 direction =
|
||||
(targetPosition - npc.position).normalisedCopy();
|
||||
targetPosition -= direction * radius;
|
||||
std::cout << action->get_name();
|
||||
}
|
||||
|
||||
public:
|
||||
ActionExecWalk(ActionExec::PlanExecData &data,
|
||||
goap::BaseAction<Blackboard> *action)
|
||||
: ActionExec(data, action)
|
||||
{
|
||||
}
|
||||
};
|
||||
struct ActionExecUse : ActionExec {
|
||||
private:
|
||||
int update(float delta) override
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
void finish(int rc) override
|
||||
{
|
||||
if (rc == OK)
|
||||
bb.apply(action->effects);
|
||||
}
|
||||
void activate() override
|
||||
{
|
||||
std::cout << action->get_name();
|
||||
const ActionNodeActions::RunActionNode *runaction =
|
||||
static_cast<const ActionNodeActions::RunActionNode
|
||||
*>(action);
|
||||
if (runaction)
|
||||
std::cout << "Is Run" << std::endl;
|
||||
OgreAssert(false, "activate");
|
||||
}
|
||||
|
||||
public:
|
||||
ActionExecUse(ActionExec::PlanExecData &data,
|
||||
goap::BaseAction<Blackboard> *action)
|
||||
: ActionExec(data, action)
|
||||
{
|
||||
}
|
||||
};
|
||||
ActionNodeActions(int node, const Blackboard &prereq, int cost)
|
||||
{
|
||||
OgreAssert(
|
||||
node < ECS::get<ActionNodeList>().dynamicNodes.size(),
|
||||
"bad node " + Ogre::StringConverter::toString(node));
|
||||
m_actions.push_back(OGRE_NEW WalkToAction(node, 10000));
|
||||
auto paction = OGRE_NEW WalkToAction(node, 10000);
|
||||
m_actions.push_back(paction);
|
||||
nlohmann::json jactionPrereq = nlohmann::json::object();
|
||||
nlohmann::json jactionEffect = nlohmann::json::object();
|
||||
jactionPrereq["at_object"] = 1;
|
||||
@@ -176,6 +349,32 @@ public:
|
||||
return m_actions;
|
||||
}
|
||||
};
|
||||
struct ActionExecCommon : ActionExec {
|
||||
private:
|
||||
int update(float delta) override
|
||||
{
|
||||
std::cout << "running: " << action->get_name() << std::endl;
|
||||
return OK;
|
||||
}
|
||||
void finish(int rc) override
|
||||
{
|
||||
if (rc == OK)
|
||||
bb.apply(action->effects);
|
||||
std::cout << "finish: " << action->get_name() << std::endl;
|
||||
}
|
||||
void activate() override
|
||||
{
|
||||
std::cout << action->get_name();
|
||||
std::cout << "!";
|
||||
}
|
||||
|
||||
public:
|
||||
ActionExecCommon(ActionExec::PlanExecData &data,
|
||||
goap::BaseAction<Blackboard> *action)
|
||||
: ActionExec(data, action)
|
||||
{
|
||||
}
|
||||
};
|
||||
CharacterAIModule::CharacterAIModule(flecs::world &ecs)
|
||||
{
|
||||
static std::mutex ecs_mutex;
|
||||
@@ -376,92 +575,6 @@ CharacterAIModule::CharacterAIModule(flecs::world &ecs)
|
||||
});
|
||||
});
|
||||
});
|
||||
struct ActionExec {
|
||||
enum { OK = 0, BUSY, ERROR };
|
||||
TownNPCs::NPCData &npc;
|
||||
Blackboard &bb;
|
||||
nlohmann::json &memory;
|
||||
bool complete;
|
||||
bool active;
|
||||
const goap::BaseAction<Blackboard> *action;
|
||||
ActionExec(TownNPCs::NPCData &npc, Blackboard &bb,
|
||||
nlohmann::json &memory,
|
||||
const goap::BaseAction<Blackboard> *action)
|
||||
: npc(npc)
|
||||
, bb(bb)
|
||||
, memory(memory)
|
||||
, complete(false)
|
||||
, active(false)
|
||||
, action(action)
|
||||
{
|
||||
}
|
||||
ActionExec(const ActionExec &other)
|
||||
: npc(other.npc)
|
||||
, bb(other.bb)
|
||||
, memory(other.memory)
|
||||
, complete(other.complete)
|
||||
, active(other.active)
|
||||
, action(other.action)
|
||||
{
|
||||
}
|
||||
ActionExec &operator=(const ActionExec &other)
|
||||
{
|
||||
npc = other.npc;
|
||||
bb = other.bb;
|
||||
memory = other.memory;
|
||||
complete = other.complete;
|
||||
active = other.active;
|
||||
action = other.action;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
int update(float delta)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
void finish(int result)
|
||||
{
|
||||
}
|
||||
void activate()
|
||||
{
|
||||
std::cout << action->get_name();
|
||||
OgreAssert(false, "activate");
|
||||
}
|
||||
|
||||
public:
|
||||
int operator()(float delta)
|
||||
{
|
||||
if (!active)
|
||||
activate();
|
||||
int ret = update(delta);
|
||||
if (ret != BUSY)
|
||||
finish(ret);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
struct PlanExec {
|
||||
enum { OK = 0, BUSY, ERROR };
|
||||
std::vector<struct ActionExec> action_exec;
|
||||
int index;
|
||||
PlanExec()
|
||||
: index(-1)
|
||||
{
|
||||
}
|
||||
int operator()(float delta)
|
||||
{
|
||||
if (index == -1)
|
||||
index = 0;
|
||||
int rc = action_exec[index](delta);
|
||||
if (rc == ActionExec::ERROR)
|
||||
return ERROR;
|
||||
if (action_exec[index].complete)
|
||||
index++;
|
||||
if (index >= action_exec.size())
|
||||
return OK;
|
||||
return BUSY;
|
||||
}
|
||||
};
|
||||
static std::unordered_map<int, struct PlanExec> plan_exec;
|
||||
ecs.system<const EngineData, TownNPCs, TownAI>("RunPLAN")
|
||||
.kind(flecs::OnUpdate)
|
||||
@@ -470,7 +583,14 @@ CharacterAIModule::CharacterAIModule(flecs::world &ecs)
|
||||
for (const auto &plans : ai.plans) {
|
||||
if (plan_exec.find(plans.first) !=
|
||||
plan_exec.end()) {
|
||||
plan_exec[plans.first](eng.delta);
|
||||
int rc = plan_exec[plans.first](
|
||||
eng.delta);
|
||||
if (rc != PlanExec::BUSY) {
|
||||
plan_exec.erase(plans.first);
|
||||
ai.plans[plans.first].erase(
|
||||
ai.plans[plans.first]
|
||||
.begin());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
std::cout << "NPC: " << plans.first;
|
||||
@@ -482,14 +602,45 @@ CharacterAIModule::CharacterAIModule(flecs::world &ecs)
|
||||
std::cout << " Goal: ";
|
||||
plan.goal->goal.dump_bits();
|
||||
for (const auto &action : plan.plan) {
|
||||
pexec.action_exec.emplace_back(
|
||||
ActionExec::PlanExecData data({
|
||||
npcs.npcs.at(
|
||||
plans.first),
|
||||
ai.blackboards.at(
|
||||
plans.first),
|
||||
ai.memory.at(
|
||||
plans.first),
|
||||
action);
|
||||
|
||||
});
|
||||
// TODO: executor factory is needed
|
||||
if (action->get_name().substr(
|
||||
0, 4) == "Walk") {
|
||||
ActionExec *e = OGRE_NEW
|
||||
ActionNodeActions::ActionExecWalk(
|
||||
data,
|
||||
action);
|
||||
pexec.action_exec
|
||||
.push_back(e);
|
||||
} else if (action->get_name()
|
||||
.substr(0,
|
||||
4) ==
|
||||
"Use(") {
|
||||
ActionExec *e = OGRE_NEW
|
||||
ActionNodeActions::ActionExecUse(
|
||||
data,
|
||||
action);
|
||||
pexec.action_exec
|
||||
.push_back(e);
|
||||
} else {
|
||||
std::cout
|
||||
<< action->get_name()
|
||||
<< " ";
|
||||
ActionExec *e = OGRE_NEW
|
||||
ActionExecCommon(
|
||||
data,
|
||||
action);
|
||||
pexec.action_exec
|
||||
.push_back(e);
|
||||
}
|
||||
std::cout << action->get_name()
|
||||
<< " ";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user