Skip to content

Commit 345d793

Browse files
committed
feat: add _onStart precondition for script execution
Add a new precondition type _onStart that allows executing scripts before a node starts its tick. This provides symmetry with the existing _post functionality.
1 parent 87d2f03 commit 345d793

File tree

3 files changed

+49
-18
lines changed

3 files changed

+49
-18
lines changed

include/behaviortree_cpp/tree_node.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,12 @@ enum class PreCond
5050
SUCCESS_IF,
5151
SKIP_IF,
5252
WHILE_TRUE,
53+
ON_START,
5354
COUNT_
5455
};
5556

56-
static const std::array<std::string, 4> PreCondNames = { //
57-
"_failureIf", "_successIf", "_skipIf", "_while"
57+
static const std::array<std::string, 5> PreCondNames = { //
58+
"_failureIf", "_successIf", "_skipIf", "_while", "_onStart"
5859
};
5960

6061
enum class PostCond

src/tree_node.cpp

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -208,24 +208,27 @@ Expected<NodeStatus> TreeNode::checkPreConditions()
208208
// Some preconditions are applied only when the node state is IDLE or SKIPPED
209209
if(_p->status == NodeStatus::IDLE || _p->status == NodeStatus::SKIPPED)
210210
{
211-
// what to do if the condition is true
212-
if(parse_executor(env).cast<bool>())
211+
auto execute_result = parse_executor(env);
212+
if(preID == PreCond::ON_START)
213213
{
214-
if(preID == PreCond::FAILURE_IF)
215-
{
216-
return NodeStatus::FAILURE;
217-
}
218-
else if(preID == PreCond::SUCCESS_IF)
219-
{
220-
return NodeStatus::SUCCESS;
221-
}
222-
else if(preID == PreCond::SKIP_IF)
223-
{
224-
return NodeStatus::SKIPPED;
225-
}
214+
return nonstd::make_unexpected(""); // no precondition
215+
}
216+
auto bool_result = execute_result.cast<bool>();
217+
// what to do if the condition is true and the precondition is xx_IF
218+
if(bool_result && preID == PreCond::FAILURE_IF)
219+
{
220+
return NodeStatus::FAILURE;
221+
}
222+
if(bool_result && preID == PreCond::SUCCESS_IF)
223+
{
224+
return NodeStatus::SUCCESS;
225+
}
226+
if(bool_result && preID == PreCond::SKIP_IF)
227+
{
228+
return NodeStatus::SKIPPED;
226229
}
227-
// if the conditions is false
228-
else if(preID == PreCond::WHILE_TRUE)
230+
// if the condition is false and the precondition is WHILE_TRUE, skip the node
231+
if(!bool_result && preID == PreCond::WHILE_TRUE)
229232
{
230233
return NodeStatus::SKIPPED;
231234
}

tests/gtest_preconditions.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,3 +397,30 @@ TEST(Preconditions, WhileCallsOnHalt)
397397
ASSERT_EQ(status, BT::NodeStatus::SKIPPED);
398398
ASSERT_EQ(tree.rootBlackboard()->get<int>("B"), 69);
399399
}
400+
401+
TEST(Preconditions, OnStart)
402+
{
403+
BehaviorTreeFactory factory;
404+
std::array<int, 3> counters;
405+
RegisterTestTick(factory, "Test", counters);
406+
static constexpr auto xml_text = R"(
407+
<root BTCPP_format="4">
408+
<BehaviorTree ID="Main">
409+
<Sequence>
410+
<AlwaysSuccess _onStart="B:=69"/>
411+
<TestA/>
412+
<TestB _successIf="B==69"/>
413+
<TestC _onStart="C:=70" _post="B=70"/>
414+
</Sequence>
415+
</BehaviorTree>
416+
</root>
417+
)";
418+
auto tree = factory.createTreeFromText(xml_text);
419+
const auto status = tree.tickWhileRunning();
420+
ASSERT_EQ(status, NodeStatus::SUCCESS);
421+
ASSERT_EQ(tree.rootBlackboard()->get<int>("B"), 70);
422+
ASSERT_EQ(tree.rootBlackboard()->get<int>("C"), 70);
423+
ASSERT_EQ(counters[0], 1);
424+
ASSERT_EQ(counters[1], 0);
425+
ASSERT_EQ(counters[2], 1);
426+
}

0 commit comments

Comments
 (0)