behaviac/src/behaviortree/behaviortree_task.cpp
aozhiwei 347c6d0b32 1
2023-12-06 19:08:54 +08:00

1664 lines
49 KiB
C++

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Tencent is pleased to support the open source community by making behaviac available.
//
// Copyright (C) 2015-2017 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at http://opensource.org/licenses/BSD-3-Clause
//
// Unless required by applicable law or agreed to in writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and limitations under the License.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "behaviac/behaviortree/behaviortree.h"
#include "behaviac/behaviortree/behaviortree_task.h"
#include "behaviac/agent/registermacros.h"
#include "behaviac/behaviortree/attachments/event.h"
#include "behaviac/common/profiler/profiler.h"
#include "behaviac/behaviortree/attachments/effector.h"
#include "behaviac/fsm/state.h"
#include "behaviac/behaviortree/attachments/effector.h"
#include "behaviac/fsm/startcondition.h"
#include "behaviac/fsm/transitioncondition.h"
#include "behaviac/behaviortree/nodes/composites/referencebehavior.h"
#include "behaviac/common/member.h"
#if BEHAVIAC_CCDEFINE_MSVC
#include <windows.h>
#endif//BEHAVIAC_CCDEFINE_MSVC
namespace behaviac {
BehaviorTask::BehaviorTask() : m_status(BT_INVALID), m_node(0), m_parent(0), m_attachments(0), m_id((uint16_t) - 1), m_bHasManagingParent(false) {
}
BehaviorTask::~BehaviorTask() {
this->FreeAttachments();
}
void BehaviorTask::FreeAttachments() {
if (this->m_attachments) {
for (size_t i = 0; i < this->m_attachments->size(); ++i) {
BehaviorTask* pAttachment = (*m_attachments)[i];
BEHAVIAC_DELETE(pAttachment);
}
this->m_attachments->clear();
BEHAVIAC_DELETE(this->m_attachments);
this->m_attachments = 0;
}
}
void BehaviorTask::Clear() {
this->m_status = BT_INVALID;
this->m_parent = 0;
this->m_id = (uint16_t) - 1;
this->FreeAttachments();
this->m_node = 0;
}
void BehaviorTask::Init(const BehaviorNode* node) {
BEHAVIAC_ASSERT(node);
this->m_node = (const BehaviorNode*)node;
this->m_id = this->m_node->GetId();
}
void BehaviorTask::DestroyTask(BehaviorTask* task) {
BEHAVIAC_DELETE(task);
}
void BehaviorTask::Attach(AttachmentTask* pAttachment) {
if (!this->m_attachments) {
this->m_attachments = BEHAVIAC_NEW Attachments;
}
this->m_attachments->push_back(pAttachment);
}
const BehaviorTask* BehaviorTask::GetTaskById(int id) const {
BEHAVIAC_ASSERT(id != -1);
if (this->m_id == id) {
return this;
}
return 0;
}
int BehaviorTask::GetNextStateId() const {
return -1;
}
const behaviac::string& BehaviorTask::GetClassNameString() const {
if (this->m_node) {
return this->m_node->GetClassNameString();
}
static behaviac::string s_subBT("SubBT");
return s_subBT;
}
uint16_t BehaviorTask::GetId() const {
return this->m_id;
}
void BehaviorTask::SetId(uint16_t id) {
this->m_id = id;
}
const BehaviorNode* BehaviorTask::GetNode() const {
return this->m_node;
}
void BehaviorTask::onreset(Agent* pAgent) {
BEHAVIAC_UNUSED_VAR(pAgent);
}
bool BehaviorTask::onenter(Agent* pAgent) {
BEHAVIAC_UNUSED_VAR(pAgent);
return true;
}
//max number of threads used for BT ticking.
//usually, only 1 thread is used for BT ticking.
const static uint32_t kMaxThreads = 32;
struct ThreadStatus_t {
THREAD_ID_TYPE tid_;
EBTStatus status_;
int nodeId_;
};
//thread safe and no more mutex or memory allocation
//
static behaviac::Mutex* gs_tickingMutex = 0;
static ThreadStatus_t gs_lastStatus[kMaxThreads];
static behaviac::Mutex& GetTickingMutex() {
if (!gs_tickingMutex) {
gs_tickingMutex = BEHAVIAC_NEW behaviac::Mutex;
}
return *gs_tickingMutex;
}
void CleanupTickingMutex() {
BEHAVIAC_DELETE gs_tickingMutex;
gs_tickingMutex = 0;
}
EBTStatus GetNodeExitStatus() {
THREAD_ID_TYPE tid = behaviac::GetTID();
{
behaviac::ScopedLock lock(GetTickingMutex());
for (uint32_t i = 0; i < kMaxThreads; ++i) {
const ThreadStatus_t& ts = gs_lastStatus[i];
if (ts.tid_ == tid) {
return ts.status_;
}
}
}
BEHAVIAC_ASSERT(false, "this function is only valid when it is called instead of an 'ExitAction' of any Node.\n \
it should not be called in any other functions!");
return BT_INVALID;
}
uint32_t SetNodeId(uint32_t nodeId) {
THREAD_ID_TYPE tid = behaviac::GetTID();
uint32_t slot = (uint32_t) - 1;
{
behaviac::ScopedLock lock(GetTickingMutex());
for (uint32_t i = 0; i < kMaxThreads; ++i) {
ThreadStatus_t& ts = gs_lastStatus[i];
if (ts.tid_ == 0) {
ts.tid_ = tid;
ts.nodeId_ = nodeId;
slot = i;
break;
}
}
}
return slot;
}
void ClearNodeId(uint32_t slot) {
THREAD_ID_TYPE tid = behaviac::GetTID();
BEHAVIAC_UNUSED_VAR(tid);
{
behaviac::ScopedLock lock(GetTickingMutex());
ThreadStatus_t& ts = gs_lastStatus[slot];
BEHAVIAC_ASSERT(ts.tid_ == tid);
ts.tid_ = 0;
ts.nodeId_ = INVALID_NODE_ID;
}
}
int GetNodeId() {
THREAD_ID_TYPE tid = behaviac::GetTID();
{
behaviac::ScopedLock lock(GetTickingMutex());
for (uint32_t i = 0; i < kMaxThreads; ++i) {
const ThreadStatus_t& ts = gs_lastStatus[i];
if (ts.tid_ == tid) {
return ts.nodeId_;
}
}
}
//BEHAVIAC_ASSERT(false, "this function is only valid when it is called instead of an 'Action' Node.\n");
return INVALID_NODE_ID;
}
EBTStatus BehaviorTask::update(Agent* pAgent, EBTStatus childStatus) {
BEHAVIAC_UNUSED_VAR(pAgent);
BEHAVIAC_UNUSED_VAR(childStatus);
return BT_SUCCESS;
}
EBTStatus BehaviorTask::update_current(Agent* pAgent, EBTStatus childStatus) {
EBTStatus s = this->update(pAgent, childStatus);
return s;
}
void BehaviorTask::onexit(Agent* pAgent, EBTStatus status) {
BEHAVIAC_UNUSED_VAR(pAgent);
BEHAVIAC_UNUSED_VAR(status);
}
#if !BEHAVIAC_RELEASE
behaviac::string BehaviorTask::GetTickInfo(const behaviac::Agent* pAgent, const behaviac::BehaviorTask* b, const char* action) {
return BehaviorTask::GetTickInfo(pAgent, b->GetNode(), action);
}
const behaviac::string GetParentTreeName(const Agent* pAgent, const BehaviorNode* n) {
behaviac::string btName;
if (ReferencedBehavior::DynamicCast(n)) {
n = n->GetParent();
}
bool bIsTree = false;
bool bIsRefTree = false;
while (n != 0) {
bIsTree = BehaviorTree::DynamicCast(n) != 0;
bIsRefTree = ReferencedBehavior::DynamicCast(n) != 0;
if (bIsTree || bIsRefTree) {
break;
}
n = n->GetParent();
}
if (bIsTree) {
const BehaviorTree* bt = BehaviorTree::DynamicCast(n);
btName = bt->GetName();
} else if (bIsRefTree) {
const ReferencedBehavior* refTree = ReferencedBehavior::DynamicCast(n);
btName = refTree->GetReferencedTree(pAgent);
} else {
BEHAVIAC_ASSERT(false);
}
return btName;
}
behaviac::string BehaviorTask::GetTickInfo(const behaviac::Agent* pAgent, const behaviac::BehaviorNode* n, const char* action) {
if (pAgent && pAgent->IsMasked()) {
char temp[1024];
//BEHAVIAC_PROFILE("GetTickInfo", true);
const behaviac::string& bClassName = n->GetClassNameString();
//filter out intermediate bt, whose class name is empty
if (!bClassName.empty()) {
const behaviac::string& btName = GetParentTreeName(pAgent, n);
int nodeId = n->GetId();
//TestBehaviorGroup\scratch.xml->EventetTask[0]:enter
behaviac::string bpstr;
if (!StringUtils::IsNullOrEmpty(btName.c_str())) {
string_sprintf(temp, "%s.xml->", btName.c_str());
bpstr = temp;
}
string_sprintf(temp, "%s[%i]", bClassName.c_str(), nodeId);
bpstr += temp;
if (!StringUtils::IsNullOrEmpty(action)) {
string_sprintf(temp, ":%s", action);
bpstr += temp;
}
return bpstr;
}
}
return behaviac::string();
}
#define _MY_BREAKPOINT_BREAK_(pAgent, btMsg, actionResult) \
{ \
Workspace::GetInstance()->WaitforContinue(); \
}
//CheckBreakpoint should be after log of onenter/onexit/update, as it needs to flush msg to the client
void CHECK_BREAKPOINT(Agent* pAgent, const BehaviorNode* b, const char* action, EActionResult actionResult) {
if (Config::IsLoggingOrSocketing()) {
behaviac::string bpstr = behaviac::BehaviorTask::GetTickInfo(pAgent, b, action);
if (!bpstr.empty()) {
LogManager::GetInstance()->Log(pAgent, bpstr.c_str(), actionResult, ELM_tick);
if (Workspace::GetInstance()->CheckBreakpoint(pAgent, b, action, actionResult)) {
//log the current variables, otherwise, its value is not the latest
pAgent->LogVariables(false);
LogManager::GetInstance()->Log(pAgent, bpstr.c_str(), actionResult, ELM_breaked);
LogManager::GetInstance()->Flush(pAgent);
behaviac::Socket::Flush();
BreakpointPromptHandler_fn fn = GetBreakpointPromptHandler();
if (fn == 0) {
_MY_BREAKPOINT_BREAK_(pAgent, bpstr.c_str(), actionResult);
} else {
fn(bpstr.c_str());
}
LogManager::GetInstance()->Log(pAgent, bpstr.c_str(), actionResult, ELM_continue);
LogManager::GetInstance()->Flush(pAgent);
behaviac::Socket::Flush();
}
}
}
}
#else
void CHECK_BREAKPOINT(Agent* pAgent, const BehaviorNode* b, const char* action, EActionResult actionResult) {
BEHAVIAC_UNUSED_VAR(pAgent);
BEHAVIAC_UNUSED_VAR(b);
BEHAVIAC_UNUSED_VAR(action);
BEHAVIAC_UNUSED_VAR(actionResult);
}
#endif//#if !BEHAVIAC_RELEASE
bool BehaviorTask::onenter_action(Agent* pAgent) {
bool bResult = this->CheckPreconditions(pAgent, false);
if (bResult) {
this->m_bHasManagingParent = false;
this->SetCurrentTask(0);
bResult = this->onenter(pAgent);
if (!bResult) {
return false;
} else {
#if !BEHAVIAC_RELEASE
//BEHAVIAC_PROFILE_DEBUGBLOCK("Debug", true);
CHECK_BREAKPOINT(pAgent, this->m_node, "enter", bResult ? EAR_success : EAR_failure);
#endif
}
}
return bResult;
}
bool BehaviorTask::CheckPreconditions(const Agent* pAgent, bool bIsAlive) const {
bool bResult = true;
if (m_node != 0) {
if (m_node->m_preconditions.size() > 0) {
bResult = ((BehaviorNode*)m_node)->CheckPreconditions(pAgent, bIsAlive);
}
}
return bResult;
}
void BehaviorTask::onexit_action(Agent* pAgent, EBTStatus status) {
this->onexit(pAgent, status);
if (this->m_node != 0) {
Effector::EPhase phase = Effector::E_SUCCESS;
if (status == BT_FAILURE) {
phase = Effector::E_FAILURE;
} else {
BEHAVIAC_ASSERT(status == BT_SUCCESS);
}
this->m_node->ApplyEffects(pAgent, (BehaviorNode::EPhase)phase);
#if !BEHAVIAC_RELEASE
if (Config::IsLoggingOrSocketing()) {
//BEHAVIAC_PROFILE_DEBUGBLOCK("Debug", true);
if (status == BT_SUCCESS) {
CHECK_BREAKPOINT(pAgent, this->m_node, "exit", EAR_success);
} else {
CHECK_BREAKPOINT(pAgent, this->m_node, "exit", EAR_failure);
}
}
#endif
}
}
/*
Get the Root of branch task
*/
BranchTask* BehaviorTask::GetTopManageBranchTask() {
BranchTask* tree = 0;
BehaviorTask* task = this->m_parent;
while (task != 0) {
if (BehaviorTreeTask::DynamicCast(task) != 0) {
//to overwrite the child branch
tree = (BranchTask*)task;
break;
} else if (task->m_node ? task->m_node->IsManagingChildrenAsSubTrees() : false) {
//until it is Parallel/SelectorLoop, it's child is used as tree to store current task
break;
} else if (BranchTask::DynamicCast(task) != 0) {
//this if must be after BehaviorTreeTask and IsManagingChildrenAsSubTrees
tree = (BranchTask*)task;
} else {
BEHAVIAC_ASSERT(false);
}
task = task->m_parent;
}
return tree;
}
BehaviorTreeTask* BehaviorTask::GetRootTask() {
BehaviorTask* task = this;
while (task->m_parent) {
task = task->m_parent;
}
BEHAVIAC_ASSERT(BehaviorTreeTask::DynamicCast(task));
BehaviorTreeTask* tree = (BehaviorTreeTask*)task;
return tree;
}
#if BEHAVIAC_ENABLE_PROFILING
// Helper class for automatically beginning and ending a profiling block
class AutoProfileBlockSend {
public:
// Construct. begin a profiling block with the specified name and optional call count.
AutoProfileBlockSend(Profiler* profiler, const char* taskClassid, const Agent* agent) : profiler_(profiler) {
if (Config::IsProfiling()) {
profiler_ = profiler;
if (profiler_) {
profiler_->BeginBlock(taskClassid, agent);
}
}
}
// Destruct. end the profiling block.
~AutoProfileBlockSend() {
if (Config::IsProfiling()) {
if (profiler_) {
profiler_->EndBlock(true);
}
}
}
private:
// Profiler.
Profiler* profiler_;
};
#endif
EBTStatus BehaviorTask::exec(Agent* pAgent) {
EBTStatus childStatus = BT_RUNNING;
return this->exec(pAgent, childStatus);
}
EBTStatus BehaviorTask::exec(Agent* pAgent, EBTStatus childStatus) {
#if !BEHAVIAC_RELEASE
char temp[1024];
#endif
#if BEHAVIAC_ENABLE_PROFILING
const char* classStr = (this->m_node ? this->m_node->GetClassNameString().c_str() : "BT");
int nodeId = (this->m_node ? this->m_node->GetId() : -1);
string_sprintf(temp, "%s[%i]", classStr, nodeId);
AutoProfileBlockSend profiler_block(Profiler::GetInstance(), temp, pAgent);
#endif//#if BEHAVIAC_ENABLE_PROFILING
#if !BEHAVIAC_RELEASE
string_sprintf(temp, "Agent In BT:%s while the Agent used for: %s", this->m_node->m_agentType.c_str(), pAgent->GetClassTypeName());
BEHAVIAC_ASSERT(!this->m_node || this->m_node->IsValid(pAgent, this), temp);
#endif
bool bEnterResult = false;
if (this->m_status == BT_RUNNING) {
bEnterResult = true;
} else {
//reset it to invalid when it was success/failure
this->m_status = BT_INVALID;
bEnterResult = this->onenter_action(pAgent);
}
if (bEnterResult) {
#if !BEHAVIAC_RELEASE
if (Config::IsLoggingOrSocketing()) {
string btStr = BehaviorTask::GetTickInfo(pAgent, this, "update");
//empty btStr is for internal BehaviorTreeTask
if (!StringUtils::IsNullOrEmpty(btStr.c_str())) {
LogManager::GetInstance()->Log(pAgent, btStr.c_str(), EAR_none, ELM_tick);
}
}
#endif
bool bValid = this->CheckParentUpdatePreconditions(pAgent);
if (bValid) {
this->m_status = this->update_current(pAgent, childStatus);
} else {
this->m_status = BT_FAILURE;
if (this->GetCurrentTask()) {
this->update_current(pAgent, BT_FAILURE);
}
}
if (this->m_status != BT_RUNNING) {
//clear it
this->onexit_action(pAgent, this->m_status);
//this node is possibly ticked by its parent or by the topBranch who records it as currrent node
//so, we can't here reset the topBranch's current node
} else {
BranchTask* tree = this->GetTopManageBranchTask();
if (tree != 0) {
tree->SetCurrentTask(this);
}
}
} else {
this->m_status = BT_FAILURE;
}
return this->m_status;
}
bool BehaviorTask::CheckParentUpdatePreconditions(Agent* pAgent) {
bool bValid = true;
if (this->m_bHasManagingParent) {
bool bHasManagingParent = false;
const int kMaxParentsCount = 512;
int parentsCount = 0;
BehaviorTask* parents[kMaxParentsCount];
BranchTask* parentBranch = this->GetParent();
parents[parentsCount++] = this;
//back track the parents until the managing branch
while (parentBranch != 0) {
BEHAVIAC_ASSERT(parentsCount < kMaxParentsCount, "weird tree!");
parents[parentsCount++] = parentBranch;
if (parentBranch->GetCurrentTask() == this) {
//BEHAVIAC_ASSERT(parentBranch->GetNode()->IsManagingChildrenAsSubTrees());
bHasManagingParent = true;
break;
}
parentBranch = parentBranch->GetParent();
}
if (bHasManagingParent) {
for (int i = parentsCount - 1; i >= 0; --i) {
BehaviorTask* pb = parents[i];
bValid = pb->CheckPreconditions(pAgent, true);
if (!bValid) {
break;
}
}
}
} else {
bValid = this->CheckPreconditions(pAgent, true);
}
return bValid;
}
bool getRunningNodes_handler(BehaviorTask* node, Agent* pAgent, void* user_data) {
BEHAVIAC_UNUSED_VAR(pAgent);
if (node->m_status == BT_RUNNING) {
(*(behaviac::vector<BehaviorTask*>*)(user_data)).push_back(node);
}
return true;
}
bool end_handler(BehaviorTask* node, Agent* pAgent, void* user_data) {
BEHAVIAC_UNUSED_VAR(user_data);
if (node->m_status == BT_RUNNING || node->m_status == BT_INVALID) {
EBTStatus status = *(EBTStatus*)user_data;
node->onexit_action(pAgent, status);
node->m_status = status;
node->SetCurrentTask(0);
}
return true;
}
bool abort_handler(BehaviorTask* node, Agent* pAgent, void* user_data) {
BEHAVIAC_UNUSED_VAR(user_data);
if (node->m_status == BT_RUNNING) {
node->onexit_action(pAgent, BT_FAILURE);
node->m_status = BT_FAILURE;
node->SetCurrentTask(0);
}
return true;
}
bool reset_handler(BehaviorTask* node, Agent* pAgent, void* user_data) {
BEHAVIAC_UNUSED_VAR(user_data);
BEHAVIAC_UNUSED_VAR(pAgent);
node->m_status = BT_INVALID;
node->SetCurrentTask(0);
node->onreset(pAgent);
return true;
}
behaviac::vector<BehaviorTask*> BehaviorTask::GetRunningNodes(bool onlyLeaves) {
behaviac::vector<BehaviorTask*> nodes;
this->traverse(true, &getRunningNodes_handler, NULL, &nodes);
if (onlyLeaves && nodes.size() > 0) {
behaviac::vector<BehaviorTask*> leaves;
for (unsigned int i = 0; i < nodes.size(); ++i) {
if (LeafTask::DynamicCast(nodes[i])) {
leaves.push_back(nodes[i]);
}
}
return leaves;
}
return nodes;
}
void BehaviorTask::abort(Agent* pAgent) {
this->traverse(true, &abort_handler, pAgent, 0);
}
void BehaviorTask::reset(Agent* pAgent) {
#if BEHAVIAC_ENABLE_PROFILING
BEHAVIAC_PROFILE("BehaviorTask::reset");
#endif
this->traverse(true, &reset_handler, pAgent, 0);
}
AttachmentTask::AttachmentTask() : BehaviorTask()
{}
void AttachmentTask::Init(const BehaviorNode* node) {
super::Init(node);
}
AttachmentTask::~AttachmentTask()
{}
void AttachmentTask::traverse(bool childFirst, NodeHandler_t handler, Agent* pAgent, void* user_data) {
BEHAVIAC_UNUSED_VAR(childFirst);
handler(this, pAgent, user_data);
}
BranchTask::BranchTask() : BehaviorTask(), m_currentNodeId(-1), m_currentTask(0) {
}
int BranchTask::GetCurrentNodeId() {
return this->m_currentNodeId;
}
void BranchTask::SetCurrentNodeId(int id) {
this->m_currentNodeId = id;
}
BranchTask::~BranchTask() {
}
bool BranchTask::onenter(Agent* pAgent) {
BEHAVIAC_UNUSED_VAR(pAgent);
//return super::onenter(pAgent);
return true;
}
void BranchTask::onexit(Agent* pAgent, EBTStatus s) {
BEHAVIAC_UNUSED_VAR(pAgent);
BEHAVIAC_UNUSED_VAR(s);
//super::onexit(pAgent, s);
}
//
//Set the m_currentTask as task
//if the leaf node is runninng ,then we should set the leaf's parent node also as running
//
void BranchTask::SetCurrentTask(BehaviorTask* task) {
if (task != 0) {
//if the leaf node is running, then the leaf's parent node is also as running,
//the leaf is set as the tree's current task instead of its parent
if (this->m_currentTask == 0) {
BEHAVIAC_ASSERT(this->m_currentTask != this);
this->m_currentTask = task;
task->SetHasManagingParent(true);
}
} else {
if (this->m_status != BT_RUNNING) {
this->m_currentTask = task;
}
}
}
EBTStatus BehaviorTask::GetStatus() const {
return this->m_status;
}
// static bool getBooleanFromStatus(EBTStatus status)
// {
// if (status == BT_FAILURE) {
// return false;
// } else if (status == BT_SUCCESS) {
// return true;
// } else {
// BEHAVIAC_ASSERT(false);
// return false;
// }
// }
bool BehaviorTask::CheckEvents(const char* eventName, Agent* pAgent, behaviac::map<uint32_t, IInstantiatedVariable*>* eventParams) const {
return this->m_node->CheckEvents(eventName, pAgent, eventParams);
}
void BehaviorTask::copyto(BehaviorTask* target) const {
target->m_status = this->m_status;
}
void BehaviorTask::save(IIONode* node) const {
if (this->m_status != BT_INVALID) {
CIOID classId("class");
node->setAttr(classId, this->GetClassNameString());
CIOID idId("id");
node->setAttr(idId, this->GetId());
CIOID statusId("status");
node->setAttr(statusId, this->m_status);
}
}
void BehaviorTask::load(IIONode* node) {
CIOID attrId("status");
behaviac::string attrStr;
if (node->getAttr(attrId, attrStr)) {
behaviac::StringUtils::ParseString(attrStr.c_str(), this->m_status);
}
#if !BEHAVIAC_RELEASE
if (this->m_status != BT_INVALID) {
CIOID classId("class");
node->getAttr(classId, attrStr);
BEHAVIAC_ASSERT(attrStr == this->GetClassNameString());
CIOID idId("id");
node->getAttr(idId, attrStr);
int id = -1;
StringUtils::ParseString(attrStr.c_str(), id);
BEHAVIAC_ASSERT(id == this->GetId());
}
#endif
}
void AttachmentTask::copyto(BehaviorTask* target) const {
super::copyto(target);
}
void AttachmentTask::save(IIONode* node) const {
super::save(node);
}
void AttachmentTask::load(IIONode* node) {
super::load(node);
}
void LeafTask::copyto(BehaviorTask* target) const {
super::copyto(target);
}
void LeafTask::save(IIONode* node) const {
super::save(node);
}
void LeafTask::load(IIONode* node) {
super::load(node);
}
struct getnode_t {
int id_;
BehaviorTask* task_;
getnode_t(int id) : id_(id), task_(0)
{}
getnode_t& operator=(const getnode_t&);
};
bool getid_handler(BehaviorTask* task, Agent* pAgent, void* user_data) {
BEHAVIAC_UNUSED_VAR(pAgent);
getnode_t* temp = (getnode_t*)user_data;
int oldId = task->GetId();
if (oldId == temp->id_) {
temp->task_ = task;
return false;
}
return true;
}
void BranchTask::copyto(BehaviorTask* target) const {
super::copyto(target);
BEHAVIAC_ASSERT(BranchTask::DynamicCast(target));
BranchTask* ttask = (BranchTask*)target;
if (this->m_currentTask) {
int id = this->m_currentTask->GetId();
getnode_t temp(id);
ttask->traverse(true, &getid_handler, 0, &temp);
BEHAVIAC_ASSERT(temp.task_);
ttask->m_currentTask = temp.task_;
}
}
void BranchTask::save(IIONode* node) const {
super::save(node);
if (this->m_status != BT_INVALID) {
int id = -1;
if (this->m_currentTask) {
id = this->m_currentTask->GetId();
}
CIOID attrId("current");
node->setAttr(attrId, id);
}
}
void BranchTask::load(IIONode* node) {
super::load(node);
if (this->m_status != BT_INVALID) {
CIOID attrId("current");
behaviac::string attrStr;
if (node->getAttr(attrId, attrStr)) {
int currentNodeId = -1;
StringUtils::ParseString(attrStr.c_str(), currentNodeId);
if (currentNodeId != -1) {
this->m_currentTask = (BehaviorTask*)this->GetTaskById(currentNodeId);
}
}
}
}
EBTStatus BranchTask::execCurrentTask(Agent* pAgent, EBTStatus childStatus) {
if (this->m_currentTask) {
BEHAVIAC_ASSERT(this->m_currentTask != 0 && this->m_currentTask->GetStatus() == BT_RUNNING);
//this->m_currentTask could be cleared in ::tick, to remember it
EBTStatus status = this->m_currentTask->exec(pAgent, childStatus);
//give the handling back to parents
if (status != BT_RUNNING) {
BEHAVIAC_ASSERT(status == BT_SUCCESS || status == BT_FAILURE);
BEHAVIAC_ASSERT(this->m_currentTask->m_status == status);
BranchTask* parentBranch = this->m_currentTask->GetParent();
this->m_currentTask = 0;
//back track the parents until the branch
while (parentBranch != 0) {
if (parentBranch == this) {
status = parentBranch->update(pAgent, status);
} else {
status = parentBranch->exec(pAgent, status);
}
if (status == BT_RUNNING) {
return BT_RUNNING;
}
BEHAVIAC_ASSERT(parentBranch == this || parentBranch->m_status == status);
if (parentBranch == this) {
break;
}
parentBranch = parentBranch->GetParent();
}
}
return status;
}
return BT_FAILURE;
}
EBTStatus BranchTask::resume_branch(Agent* pAgent, EBTStatus status) {
BEHAVIAC_ASSERT(this->m_currentTask != 0);
BEHAVIAC_ASSERT(status == BT_SUCCESS || status == BT_FAILURE);
BranchTask* parent = 0;
BehaviorNode* _tNode = (BehaviorNode*) this->m_currentTask->m_node;
if (_tNode->IsManagingChildrenAsSubTrees()) {
parent = (BranchTask*)this->m_currentTask;
} else {
parent = this->m_currentTask->GetParent();
}
//clear it as it ends and the next exec might need to set it
this->m_currentTask = 0;
EBTStatus s = parent->exec(pAgent, status);
return s;
}
EBTStatus BranchTask::update_current(Agent* pAgent, EBTStatus childStatus) {
EBTStatus status = BT_INVALID;
if (this->m_currentTask != 0) {
status = this->execCurrentTask(pAgent, childStatus);
BEHAVIAC_ASSERT(status == BT_RUNNING ||
(status != BT_RUNNING && this->m_currentTask == 0));
} else {
status = this->update(pAgent, childStatus);
}
return status;
}
int CompositeTask::InvalidChildIndex = (int) - 1;
CompositeTask::CompositeTask() : BranchTask(), m_activeChildIndex(InvalidChildIndex) {
}
void CompositeTask::Init(const BehaviorNode* node) {
super::Init(node);
BEHAVIAC_ASSERT(node->GetChildrenCount() > 0);
uint32_t childrenCount = node->GetChildrenCount();
for (uint32_t i = 0; i < childrenCount; i++) {
const BehaviorNode* childNode = node->GetChild(i);
BehaviorTask* childTask = childNode->CreateAndInitTask();
this->addChild(childTask);
}
}
void CompositeTask::copyto(BehaviorTask* target) const {
super::copyto(target);
BEHAVIAC_ASSERT(CompositeTask::DynamicCast(target));
CompositeTask* ttask = (CompositeTask*)target;
ttask->m_activeChildIndex = this->m_activeChildIndex;
BEHAVIAC_ASSERT(this->m_children.size() > 0);
BEHAVIAC_ASSERT(this->m_children.size() == ttask->m_children.size());
BehaviorTasks_t::size_type count = this->m_children.size();
for (BehaviorTasks_t::size_type i = 0; i < count; ++i) {
BehaviorTask* childTask = this->m_children[i];
BehaviorTask* childTTask = ttask->m_children[i];
childTask->copyto(childTTask);
}
}
void CompositeTask::save(IIONode* node) const {
super::save(node);
if (this->m_status != BT_INVALID) {
CIOID attrId("activeChildIndex");
node->setAttr(attrId, this->m_activeChildIndex);
BehaviorTasks_t::size_type count = this->m_children.size();
for (BehaviorTasks_t::size_type i = 0; i < count; ++i) {
BehaviorTask* childTask = this->m_children[i];
CIOID nodeId("node");
IIONode* chidlNode = node->newNodeChild(nodeId);
childTask->save(chidlNode);
}
}
}
void CompositeTask::load(IIONode* node) {
super::load(node);
if (this->m_status != BT_INVALID) {
CIOID attrId("activeChildIndex");
behaviac::string attrStr;
node->getAttr(attrId, attrStr);
StringUtils::ParseString(attrStr.c_str(), this->m_activeChildIndex);
//#if !BEHAVIAC_RELEASE
// if (this->m_activeChildIndex != uint32_t(-1))
// {
// BEHAVIAC_ASSERT(this->m_currentTask == this->m_children[this->m_activeChildIndex]);
// }
// else
// {
// BEHAVIAC_ASSERT(this->m_currentTask == 0);
// }
//#endif
BehaviorTasks_t::size_type count = this->m_children.size();
BEHAVIAC_ASSERT(count == (BehaviorTasks_t::size_type)node->getChildCount());
for (BehaviorTasks_t::size_type i = 0; i < count; ++i) {
BehaviorTask* childTask = this->m_children[i];
//CIOID nodeId("node");
IIONode* chidlNode = node->getChild((int32_t)i);
childTask->load(chidlNode);
}
}
}
CompositeTask::~CompositeTask() {
for (size_t i = 0; i < this->m_children.size(); ++i) {
BehaviorTask* pChild = this->m_children[i];
BEHAVIAC_DELETE(pChild);
}
this->m_children.clear();
}
BehaviorTask* CompositeTask::GetChildById(int nodeId) const {
if (this->m_children.size() > 0) {
for (unsigned int i = 0; i < this->m_children.size(); ++i) {
BehaviorTask* c = this->m_children[i];
if (c->GetId() == nodeId) {
return c;
}
}
}
return 0;
}
const BehaviorTask* CompositeTask::GetTaskById(int id) const {
BEHAVIAC_ASSERT(id != -1);
const BehaviorTask* t = super::GetTaskById(id);
if (t) {
return t;
}
for (size_t i = 0; i < this->m_children.size(); ++i) {
const BehaviorTask* pChild = this->m_children[i];
const BehaviorTask* t1 = pChild->GetTaskById(id);
if (t1) {
return t1;
}
}
return 0;
}
void CompositeTask::addChild(BehaviorTask* pBehavior) {
pBehavior->SetParent(this);
this->m_children.push_back(pBehavior);
}
void CompositeTask::traverse(bool childFirst, NodeHandler_t handler, Agent* pAgent, void* user_data) {
if (childFirst) {
for (BehaviorTasks_t::iterator it = this->m_children.begin();
it != this->m_children.end(); ++it) {
//BehaviorTask* task = *it;
(*it)->traverse(childFirst, handler, pAgent, user_data);
//task->traverse(handler, pAgent, user_data);
}
handler(this, pAgent, user_data);
} else {
if (handler(this, pAgent, user_data)) {
for (BehaviorTasks_t::iterator it = this->m_children.begin();
it != this->m_children.end(); ++it) {
//BehaviorTask* task = *it;
(*it)->traverse(childFirst, handler, pAgent, user_data);
//task->traverse(handler, pAgent, user_data);
}
}
}
}
SingeChildTask::SingeChildTask() : m_root(0)
{}
SingeChildTask::~SingeChildTask() {
BEHAVIAC_DELETE(m_root);
}
void SingeChildTask::addChild(BehaviorTask* pBehavior) {
pBehavior->SetParent(this);
this->m_root = pBehavior;
}
void SingeChildTask::traverse(bool childFirst, NodeHandler_t handler, Agent* pAgent, void* user_data) {
if (childFirst) {
if (this->m_root) {
this->m_root->traverse(childFirst, handler, pAgent, user_data);
}
handler(this, pAgent, user_data);
} else {
if (handler(this, pAgent, user_data)) {
if (this->m_root) {
this->m_root->traverse(childFirst, handler, pAgent, user_data);
}
}
}
}
void SingeChildTask::Init(const BehaviorNode* node) {
super::Init(node);
BEHAVIAC_ASSERT(node->GetChildrenCount() <= 1);
if (node->GetChildrenCount() == 1) {
const BehaviorNode* childNode = node->GetChild(0);
BehaviorTask* childTask = childNode->CreateAndInitTask();
this->addChild(childTask);
} else {
BEHAVIAC_ASSERT(true);
}
}
void SingeChildTask::copyto(BehaviorTask* target) const {
super::copyto(target);
BEHAVIAC_ASSERT(SingeChildTask::DynamicCast(target));
SingeChildTask* ttask = (SingeChildTask*)target;
if (this->m_root) {
//referencebehavior/query, etc.
if (!ttask->m_root) {
const BehaviorNode* pNode = this->m_root->GetNode();
BEHAVIAC_ASSERT(BehaviorTree::DynamicCast(pNode));
ttask->m_root = pNode->CreateAndInitTask();
}
BEHAVIAC_ASSERT(ttask->m_root);
this->m_root->copyto(ttask->m_root);
}
}
void SingeChildTask::save(IIONode* node) const {
super::save(node);
if (this->m_status != BT_INVALID) {
if (this->m_root) {
CIOID nodeId("root");
IIONode* chidlNode = node->newNodeChild(nodeId);
this->m_root->save(chidlNode);
}
}
}
void SingeChildTask::load(IIONode* node) {
super::load(node);
if (this->m_status != BT_INVALID) {
CIOID rootId("root");
IIONode* rootNode = node->findNodeChild(rootId);
BEHAVIAC_ASSERT(rootNode);
this->m_root->load(rootNode);
}
}
const BehaviorTask* SingeChildTask::GetTaskById(int id) const {
BEHAVIAC_ASSERT(id != -1);
const BehaviorTask* t = super::GetTaskById(id);
if (t) {
return t;
}
if (this->m_root->GetId() == id) {
return this->m_root;
}
return this->m_root->GetTaskById(id);
}
EBTStatus SingeChildTask::update(Agent* pAgent, EBTStatus childStatus) {
if (this->m_root) {
EBTStatus s = this->m_root->exec(pAgent, childStatus);
return s;
}
return BT_FAILURE;
}
DecoratorTask::DecoratorTask() : SingeChildTask(), m_bDecorateWhenChildEnds(false) {
}
void DecoratorTask::Init(const BehaviorNode* node) {
super::Init(node);
DecoratorNode* pDN = (DecoratorNode*)node;
this->m_bDecorateWhenChildEnds = pDN->m_bDecorateWhenChildEnds;
}
void DecoratorTask::copyto(BehaviorTask* target) const {
super::copyto(target);
// BEHAVIAC_ASSERT(DecoratorTask::DynamicCast(target));
// DecoratorTask* ttask = (DecoratorTask*)target;
}
void DecoratorTask::save(IIONode* node) const {
super::save(node);
}
void DecoratorTask::load(IIONode* node) {
super::load(node);
}
DecoratorTask::~DecoratorTask() {
}
bool DecoratorTask::onenter(Agent* pAgent) {
BEHAVIAC_UNUSED_VAR(pAgent);
return true;
}
EBTStatus DecoratorTask::update_current(Agent* pAgent, EBTStatus childStatus) {
return super::update_current(pAgent, childStatus);
}
EBTStatus DecoratorTask::update(Agent* pAgent, EBTStatus childStatus) {
BEHAVIAC_ASSERT(DecoratorNode::DynamicCast(this->m_node) != 0);
DecoratorNode* node = (DecoratorNode*)this->m_node;
EBTStatus status = BT_INVALID;
if (childStatus != BT_RUNNING) {
status = childStatus;
if (!node->m_bDecorateWhenChildEnds || status != BT_RUNNING) {
EBTStatus result = this->decorate(status);
if (result != BT_RUNNING) {
return result;
}
return BT_RUNNING;
}
}
status = super::update(pAgent, childStatus);
if (!node->m_bDecorateWhenChildEnds || status != BT_RUNNING) {
EBTStatus result = this->decorate(status);
return result;
}
return BT_RUNNING;
}
LeafTask::LeafTask() : BehaviorTask()
{}
void LeafTask::Init(const BehaviorNode* node) {
super::Init(node);
//BEHAVIAC_ASSERT(node && node->GetChildrenCount() == 0);
}
LeafTask::~LeafTask()
{}
void LeafTask::traverse(bool childFirst, NodeHandler_t handler, Agent* pAgent, void* user_data) {
BEHAVIAC_UNUSED_VAR(childFirst);
handler(this, pAgent, user_data);
}
BehaviorTreeTask::BehaviorTreeTask() : SingeChildTask(), m_lastTreeTask(0)
{
}
void BehaviorTreeTask::Init(const BehaviorNode* node) {
BEHAVIAC_ASSERT(node != 0);
// BehaviorTree* tree = (BehaviorTree*)node;
super::Init(node);
if (this->m_node != NULL) {
BEHAVIAC_ASSERT(BehaviorTree::DynamicCast(this->m_node));
((BehaviorTree*)this->m_node)->InstantiatePars(this->m_localVars);
}
}
void BehaviorTreeTask::copyto(BehaviorTask* target) const {
super::copyto(target);
// BEHAVIAC_ASSERT(BehaviorTreeTask::DynamicCast(target));
// BehaviorTreeTask* ttask = (BehaviorTreeTask*)target;
}
void BehaviorTreeTask::save(IIONode* node) const {
super::save(node);
if (this->m_localVars.size() > 0) {
CIOID variablesId("locals");
IIONode* varsNode = node->newNodeChild(variablesId);
for (behaviac::map<uint32_t, IInstantiatedVariable*>::const_iterator it = this->m_localVars.begin(); it != this->m_localVars.end(); ++it) {
IInstantiatedVariable* pLocal = it->second;
pLocal->Save(varsNode);
}
}
}
void BehaviorTreeTask::load(IIONode* node) {
super::load(node);
}
BehaviorTreeTask::~BehaviorTreeTask() {
//if (this->m_root)
//{
// BehaviorTask::DestroyTask(this->m_root);
//}
Clear();
}
void BehaviorTreeTask::Clear() {
if (this->m_node != NULL) {
BEHAVIAC_ASSERT(BehaviorTree::DynamicCast(this->m_node));
((BehaviorTree*)this->m_node)->UnInstantiatePars(this->m_localVars);
}
BehaviorTask::Clear();
BEHAVIAC_DELETE this->m_root;
this->m_root = 0;
this->m_currentTask = 0;
}
void BehaviorTreeTask::AddVariables(behaviac::map<uint32_t, IInstantiatedVariable*>* vars) {
if (vars != NULL) {
for (behaviac::map<uint32_t, IInstantiatedVariable*>::iterator it = vars->begin(); it != vars->end(); ++it) {
IInstantiatedVariable* pVar = this->m_localVars[it->first];
BEHAVIAC_DELETE pVar;
this->m_localVars[it->first] = it->second;
}
}
}
const behaviac::string& BehaviorTreeTask::GetName() const {
BEHAVIAC_ASSERT(BehaviorTree::DynamicCast(this->m_node));
const BehaviorTree* bt = (const BehaviorTree*)(this->m_node);
BEHAVIAC_ASSERT(bt);
return bt->GetName();
}
bool BehaviorTreeTask::onenter(Agent* pAgent) {
pAgent->LogJumpTree(this->GetName());
return true;
}
void BehaviorTreeTask::onexit(Agent* pAgent, EBTStatus status) {
pAgent->m_excutingTreeTask = this->m_lastTreeTask;
pAgent->LogReturnTree(this->GetName());
super::onexit(pAgent, status);
}
EBTStatus BehaviorTreeTask::update_current(Agent* pAgent, EBTStatus childStatus) {
BEHAVIAC_ASSERT(this->m_node != 0);
BEHAVIAC_ASSERT(BehaviorTree::DynamicCast(this->m_node) != 0);
this->m_lastTreeTask = pAgent->m_excutingTreeTask;
pAgent->m_excutingTreeTask = this;
//pAgent->m_excutingTreeTask->SetParent(this->m_lastTreeTask);
BehaviorTree* tree = (BehaviorTree*)this->m_node;
EBTStatus status = BT_RUNNING;
if (tree->IsFSM()) {
status = this->update(pAgent, childStatus);
} else {
status = super::update_current(pAgent, childStatus);
}
return status;
}
void BehaviorTreeTask::setEndStatus(EBTStatus status) {
this->m_endStatus = status;
}
void BehaviorTreeTask::end(Agent* pAgent, EBTStatus status) {
this->traverse(true, &end_handler, pAgent, &status);
}
EBTStatus BehaviorTreeTask::update(Agent* pAgent, EBTStatus childStatus) {
BEHAVIAC_ASSERT(this->m_node != 0);
BEHAVIAC_ASSERT(this->m_root != 0);
if (childStatus != BT_RUNNING) {
return childStatus;
}
EBTStatus status = BT_INVALID;
this->m_endStatus = BT_INVALID;
status = super::update(pAgent, childStatus);
BEHAVIAC_ASSERT(status != BT_INVALID);
// When the End node takes effect, it always returns BT_RUNNING
// and m_endStatus should always be BT_SUCCESS or BT_FAILURE
if ((status == BT_RUNNING) && (this->m_endStatus != BT_INVALID)) {
this->end(pAgent, this->m_endStatus);
return this->m_endStatus;
}
return status;
}
void BehaviorTreeTask::SetRootTask(BehaviorTask* pRoot) {
this->addChild(pRoot);
}
void BehaviorTreeTask::CopyTo(BehaviorTreeTask* target) {
this->copyto(target);
}
EBTStatus BehaviorTreeTask::resume(Agent* pAgent, EBTStatus status) {
EBTStatus s = super::resume_branch(pAgent, status);
return s;
}
bool BehaviorTask::onevent(Agent* pAgent, const char* eventName, behaviac::map<uint32_t, IInstantiatedVariable*>* eventParams) {
if (this->m_status == BT_RUNNING && this->m_node->m_bHasEvents) {
if (!this->CheckEvents(eventName, pAgent, eventParams)) {
return false;
}
}
return true;
}
void BranchTask::Init(const BehaviorNode* node) {
super::Init(node);
}
bool BranchTask::oneventCurrentNode(Agent* pAgent, const char* eventName, behaviac::map<uint32_t, IInstantiatedVariable*>* eventParams) {
if (this->m_currentTask) {
EBTStatus s = this->m_currentTask->GetStatus();
BEHAVIAC_UNUSED_VAR(s);
BEHAVIAC_ASSERT(s == BT_RUNNING && this->m_node->HasEvents());
bool bGoOn = this->m_currentTask->onevent(pAgent, eventName, eventParams);
//give the handling back to parents
if (bGoOn && this->m_currentTask) {
BranchTask* parentBranch = this->m_currentTask->GetParent();
//back track the parents until the branch
while (parentBranch && parentBranch != this) {
BEHAVIAC_ASSERT(parentBranch->GetStatus() == BT_RUNNING);
bGoOn = parentBranch->onevent(pAgent, eventName, eventParams);
if (!bGoOn) {
return false;
}
parentBranch = parentBranch->GetParent();
}
}
return bGoOn;
}
return true;
}
bool BranchTask::onevent(Agent* pAgent, const char* eventName, behaviac::map<uint32_t, IInstantiatedVariable*>* eventParams) {
if (this->m_node->HasEvents()) {
bool bGoOn = true;
if (this->m_currentTask) {
bGoOn = this->oneventCurrentNode(pAgent, eventName, eventParams);
}
if (bGoOn) {
bGoOn = super::onevent(pAgent, eventName, eventParams);
}
}
return true;
}
bool LeafTask::onevent(Agent* pAgent, const char* eventName, behaviac::map<uint32_t, IInstantiatedVariable*>* eventParams) {
bool bGoOn = super::onevent(pAgent, eventName, eventParams);
return bGoOn;
}
bool BehaviorTreeTask::onevent(Agent* pAgent, const char* eventName, behaviac::map<uint32_t, IInstantiatedVariable*>* eventParams) {
return super::onevent(pAgent, eventName, eventParams);
}
void BehaviorTreeTask::Save(IIONode* node) const {
CIOID btId("BehaviorTree");
IIONode* btNodeRoot = node->newNodeChild(btId);
BEHAVIAC_ASSERT(BehaviorTree::DynamicCast(this->GetNode()));
BehaviorTree* bt = (BehaviorTree*)this->GetNode();
CIOID sourceId("source");
btNodeRoot->setAttr(sourceId, bt->GetName());
CIOID nodeId("node");
IIONode* btNode = btNodeRoot->newNodeChild(nodeId);
this->save(btNode);
}
static void LoadLocals(IIONode* node, behaviac::map<uint32_t, IInstantiatedVariable*>& locals) {
CIOID variablesId("locals");
IIONode* varsNode = node->findNodeChild(variablesId);
if (varsNode) {
int varsCount = varsNode->getChildCount();
for (int i = 0; i < varsCount; ++i) {
IIONode* varNode = varsNode->getChild(i);
CIOID nameId("name");
behaviac::string nameStr;
varNode->getAttr(nameId, nameStr);
CIOID valueId("value");
behaviac::string valueStr;
varNode->getAttr(valueId, valueStr);
CStringCRC memberId(nameStr.c_str());
behaviac::map<uint32_t, IInstantiatedVariable*>::iterator it = locals.find(memberId.GetUniqueID());
if (it != locals.end()) {
IInstantiatedVariable* p = it->second;
p->SetValueFromString(valueStr.c_str());
}
}
}
}
void BehaviorTreeTask::Load(IIONode* node) {
this->load(node);
LoadLocals(node, this->m_localVars);
}
}//namespace behaviac