BehaviorTree
Core Library to create and execute Behavior Trees
Loading...
Searching...
No Matches
script_precondition.h
1/* Copyright (C) 2022-2025 Davide Faconti - All Rights Reserved
2*
3* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
4* to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
5* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7*
8* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
10* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11*/
12
13#pragma once
14
15#include "behaviortree_cpp/decorator_node.h"
16#include "behaviortree_cpp/scripting/script_parser.hpp"
17
18#include <type_traits>
19
20namespace BT
21{
22/**
23 * @brief The PreconditionNode evaluates a script condition before ticking its child.
24 *
25 * If the script in the "if" port returns true, the child is ticked.
26 * If the script returns false, the node returns the status specified in the "else" port
27 * (FAILURE by default).
28 *
29 * Once the child starts (returns RUNNING), subsequent ticks will continue
30 * executing the child without re-evaluating the precondition until completion.
31 *
32 * Example usage:
33 *
34 * <Precondition if="A > B && color != BLUE" else="FAILURE">
35 * <SomeAction/>
36 * </Precondition>
37 */
39{
40public:
41 PreconditionNode(const std::string& name, const NodeConfig& config)
42 : DecoratorNode(name, config)
43 {
44 loadExecutor();
45 }
46
47 ~PreconditionNode() override = default;
48
49 PreconditionNode(const PreconditionNode&) = delete;
50 PreconditionNode& operator=(const PreconditionNode&) = delete;
51 PreconditionNode(PreconditionNode&&) = delete;
52 PreconditionNode& operator=(PreconditionNode&&) = delete;
53
54 static PortsList providedPorts()
55 {
56 return { InputPort<std::string>("if"),
57 InputPort<NodeStatus>("else", NodeStatus::FAILURE,
58 "Return status if condition is "
59 "false") };
60 }
61
62private:
63 virtual BT::NodeStatus tick() override
64 {
65 loadExecutor();
66
67 BT::NodeStatus else_return = NodeStatus::FAILURE;
68 if(!getInput("else", else_return))
69 {
70 throw RuntimeError("Missing parameter [else] in Precondition");
71 }
72
73 // Only check the 'if' script if we haven't started ticking the children yet.
74 Ast::Environment env = { config().blackboard, config().enums };
75 bool tick_children =
76 _children_running || (_children_running = _executor(env).cast<bool>());
77
78 if(!tick_children)
79 {
80 return else_return;
81 }
82
83 auto const child_status = child_node_->executeTick();
84 if(isStatusCompleted(child_status))
85 {
86 resetChild();
87 _children_running = false;
88 }
89 return child_status;
90 }
91
92 void loadExecutor()
93 {
94 std::string script;
95 if(!getInput("if", script))
96 {
97 throw RuntimeError("Missing parameter [if] in Precondition");
98 }
99 if(script == _script)
100 {
101 return;
102 }
103 auto executor = ParseScript(script);
104 if(!executor)
105 {
106 throw RuntimeError(executor.error());
107 }
108 else
109 {
110 _executor = executor.value();
111 _script = script;
112 }
113 }
114
115 std::string _script;
116 ScriptFunction _executor;
117 bool _children_running = false;
118};
119
120} // namespace BT
The DecoratorNode is the base class for nodes that have exactly one child.
Definition: decorator_node.h:19
The PreconditionNode evaluates a script condition before ticking its child.
Definition: script_precondition.h:39
virtual BT::NodeStatus executeTick()
The method that should be used to invoke tick() and setStatus();.
Definition: action_node.h:24
NodeStatus
Definition: basic_types.h:34
The Environment class is used to encapsulate the information and states needed by the scripting langu...
Definition: script_parser.hpp:32
Definition: tree_node.h:105