46 std::vector<Node *> nodes;
55 std::vector<const Node *> nodes;
65 return (it !=
node_index_.end()) ? it->second :
nullptr;
73 std::vector<Node *> result;
77 result.push_back(
const_cast<Node *
>(node));
105 Node *node_ptr = node.get();
106 found_parent->
AddChild(std::move(node));
128 for (
Node *potential_parent : all_nodes) {
129 for (
size_t i = 0; i < potential_parent->GetChildCount(); ++i) {
130 if (potential_parent->GetChild(i)->GetId() == node_id) {
131 potential_parent->RemoveChild(i);
155 result.
AddError(
"Tree has no root node");
161 result.
AddError(
"Tree contains cycles");
165 std::vector<const Node *> visited;
169 for (
const auto &error : node_result.errors) {
170 result.
errors.push_back(error);
173 for (
const auto &warning : node_result.warnings) {
194 auto cloned_tree = std::make_unique<BehaviorTree>(
name_ +
" (Copy)");
201 cloned_tree->SetRootNode(std::move(cloned_root));
226 const_root->
Accept(visitor);
234 std::stack<Node *> stack;
237 while (!stack.empty()) {
238 Node *current = stack.top();
254 std::stack<Node *> stack1, stack2;
257 while (!stack1.empty()) {
258 Node *current = stack1.top();
260 stack2.push(current);
267 while (!stack2.empty()) {
268 visitor(stack2.top());
286 std::ostringstream oss;
287 oss <<
"Tree: " <<
name_ <<
"\n";
290 oss <<
"Structure:\n" <<
root_node_->ToString();
296 std::unordered_map<Node::Type, size_t> stats;
342 if (predicate(current)) {
359 nodes.push_back(current);
369 nodes.push_back(current);
379 result.
AddError(
"Null node found in tree");
384 if (std::find(visited.begin(), visited.end(), node) != visited.end()) {
385 result.
AddError(
"Circular reference detected at node: " + node->
GetName());
388 visited.push_back(node);
401 if (child_count == 0) {
402 result.
AddError(
"Decorator node '" + node->
GetName() +
"' has no children (must have exactly 1)");
403 }
else if (child_count > 1) {
404 result.
AddWarning(
"Decorator node '" + node->
GetName() +
"' has " + std::to_string(child_count) +
405 " children (typically should have exactly 1)");
411 if (child_count == 0) {
419 if (child_count > 0) {
420 result.
AddWarning(
"Leaf node '" + node->
GetName() +
"' has " + std::to_string(child_count) +
421 " children (leaf nodes typically have no children)");
431 result.
AddError(
"Node has empty name");
435 for (
size_t i = 0; i < child_count; ++i) {
441 for (
const auto &error : child_result.errors) {
442 result.
errors.push_back(error);
445 for (
const auto &warning : child_result.warnings) {
449 result.
AddError(
"Node '" + node->
GetName() +
"' has null child at index " + std::to_string(i));
470 auto tree = std::make_unique<BehaviorTree>(
"Sample Tree");
471 tree->SetDescription(
"A sample behavior tree for demonstration");
479 root->AddChild(std::move(condition));
480 root->AddChild(std::move(action1));
481 root->AddChild(std::move(action2));
483 tree->SetRootNode(std::move(root));
488 auto tree = std::make_unique<BehaviorTree>(name);
489 tree->SetDescription(
"Empty behavior tree");
498 LOG_ERROR(
"BehaviorTree",
"Cannot add null blackboard to behavior tree");
504 LOG_ERROR(
"BehaviorTree",
"Cannot add blackboard with empty ID to behavior tree");
509 LOG_INFO(
"BehaviorTree",
"Added blackboard '" +
id +
"' to behavior tree '" +
name_ +
"'");
514 return (it !=
blackboards_.end()) ? it->second.get() :
nullptr;
519 return (it !=
blackboards_.end()) ? it->second.get() :
nullptr;
530 LOG_INFO(
"BehaviorTree",
"Removed blackboard '" +
id +
"' from behavior tree '" +
name_ +
"'");
537 LOG_INFO(
"BehaviorTree",
"Cleared " + std::to_string(count) +
" blackboards from behavior tree '" +
name_ +
"'");
#define LOG_ERROR(category, message)
#define LOG_INFO(category, message)
Blackboard * GetBlackboard(const EmberCore::String &id)
std::map< EmberCore::String, std::unique_ptr< Blackboard > > blackboards_
std::shared_ptr< Node > root_node_shared_
std::unique_ptr< Node > root_node_
void TraverseNodes(std::function< void(Node *)> visitor)
size_t GetNodeCount() const
std::vector< Node * > GetAllNodes()
Node * GetRootNode() const
std::unordered_map< size_t, Node * > node_index_
void TraversePostOrder(std::function< void(Node *)> visitor)
EmberCore::String GetMetadata(const EmberCore::String &key) const
EmberCore::String description_
bool HasBlackboard(const EmberCore::String &id) const
std::unordered_map< Node::Type, size_t > GetNodeTypeStatistics() const
void SetMetadata(const EmberCore::String &key, const EmberCore::String &value)
size_t GetMaxDepth() const
void AddBlackboard(std::unique_ptr< Blackboard > blackboard)
void BuildNodeIndex(Node *node)
ExecutionState
Tree execution states.
bool RemoveNode(size_t node_id)
EmberCore::String GetTreeStructure() const
void CollectNodesRecursive(Node *current, std::vector< Node * > &nodes)
ValidationResult ValidateNode(const Node *node, std::vector< const Node * > &visited) const
void RemoveBlackboard(const EmberCore::String &id)
bool MoveNode(size_t node_id, Node *new_parent)
BehaviorTree(const EmberCore::String &name="Behavior Tree")
Constructor.
ValidationResult Validate() const
bool AddNode(std::unique_ptr< Node > node, Node *parent=nullptr)
std::unique_ptr< BehaviorTree > Clone() const
void TraversePreOrder(std::function< void(Node *)> visitor)
void SetRootNode(std::unique_ptr< Node > root)
ExecutionState execution_state_
std::unordered_map< EmberCore::String, EmberCore::String > metadata_
TreeChangeCallback tree_change_callback_
std::vector< Node * > FindNodesByType(Node::Type type) const
void NotifyTreeChange(const EmberCore::String &change_type)
Node * FindNodeById(size_t id) const
NodeChangeCallback node_change_callback_
Node * FindNodeByName(const EmberCore::String &name) const
void NotifyNodeChange(Node *node, const EmberCore::String &change_type)
void RemoveMetadata(const EmberCore::String &key)
Node * FindNodeRecursive(Node *current, std::function< bool(const Node *)> predicate) const
~BehaviorTree()
Destructor.
Represents a blackboard containing multiple entries.
void Error(const EmberCore::String &category, const EmberCore::String &message)
static Logger & GetInstance()
void Info(const EmberCore::String &category, const EmberCore::String &message)
static std::unique_ptr< Node > CreateConditionNode(const String &name)
static std::unique_ptr< Node > CreateActionNode(const String &name)
static std::unique_ptr< Node > CreateControlNode(const String &name)
Represents a node in a behavior tree structure.
void SetVisualState(VisualState state)
size_t GetSubtreeNodeCount() const
Node * GetChild(size_t index) const
Type
Node types for behavior tree classification.
void Accept(std::function< void(Node *)> visitor)
const String & GetName() const
void AddChild(std::unique_ptr< Node > child)
size_t GetChildCount() const
void SetStatus(Status status)
std::unique_ptr< BehaviorTree > CreateSampleTree()
Create a sample behavior tree for testing.
std::unique_ptr< BehaviorTree > CreateEmptyTree(const EmberCore::String &name="New Tree")
Create an empty behavior tree with basic structure.
Main types header for EmberCore.
std::string String
Framework-agnostic string type.
void AddError(const EmberCore::String &error)
void AddWarning(const EmberCore::String &warning)
std::vector< EmberCore::String > errors
std::vector< EmberCore::String > warnings