Changelog: 4.9.0 (since 4.8.4)
New Features
-
New node TryCatch: similar to a Sequence, but with a "cleanup" node that is execute only if the Sequence failed or was halted. A feature requested by many users!
-
Polymorphic shared_ptr port support. Nodes producing
shared_ptr<Derived>can now connect to ports expectingshared_ptr<Base>. Register inheritance relationships withfactory.registerPolymorphicCast<Derived, Base>()and the library handles upcasting/downcasting transparently, including transitive chains (e.g. Sphynx -> Cat -> Animal). Issue #943, PR #1107. -
Exception tracking in nodes. When an exception is thrown during
tick(), it is now wrapped in aNodeExecutionErrorthat includes the failing node's name, path, and registration name. Issue #990, PR #1106. -
Replaced lexy scripting dependency with a hand-written Pratt parser. The lexy third-party dependency has been removed and replaced with a custom tokenizer and recursive-descent Pratt parser. This reduces compilation time, binary size, and eliminates a non-trivial dependency. PR #1099.
Bug Fixes
-
EntryUpdatedDecorator::halt() not halting its child. The decorator was missing the call to
DecoratorNode::halt(), leaving the child node running when the decorator was halted. Issue #1111, PR #1112. -
Use-after-free when factory destroyed before tree. After
createTree(), node manifest pointers pointed into the factory's internal map. If the factory was destroyed before ticking, these became dangling pointers.Tree::remapManifestPointers()now re-points each node's manifest to the tree's own copy. Issue #1046, PR #1081. -
createTreeFromText could not find previously registered subtrees.
createTreeFromText()andcreateTreeFromFile()used a temporary parser that couldn't see subtrees registered viaregisterBehaviorTreeFromText()/registerBehaviorTreeFromFile(). They now use the factory's shared parser. Issue #880, PR #1105. -
Groot2Publisher destructor infinite loop. The destructor could hang indefinitely when the ZMQ server thread was waiting on
recv(). Fixed by callingzmq_context.shutdown()to interrupt blocking receives. Issue #1057, PRs #1100, #1058. -
Recursive subtree cycles now detected at parse time. Previously, mutually-recursive subtrees caused a stack overflow at tree instantiation. The parser now tracks an ancestor set and throws a clear
RuntimeErrorwhen a cycle is detected. Issue #979, PR #1085. -
Deeply-nested XML no longer causes stack overflow. A depth limit (256) is now enforced during XML parsing and tree instantiation. Issue #672, PR #1091.
-
Script parser left-associativity for arithmetic operators. Expressions like
A - B + Cwere evaluated asA - (B + C)instead of(A - B) + C. Issue #1029, PR #1069. -
Mock substitution hangs when TestNodeConfigs is absent. An empty
TestNodeConfigsobject was always created, causing mock nodes to be registered even when no test configuration was intended, which led to infinite loops. Issue #930, PR #1086. -
Segfault when substituting a SubTree node. When a substitution rule replaced a SubTree with a TestNode,
setSubtreeIDwas called on a null pointer. Issue #934, PR #1083. -
BehaviorTreeFactory could not be returned by value. Move constructor and move assignment were defaulted in the header where PImpl is an incomplete type, preventing compilation. Issue #937, PR #1082.
-
getLockedPortContent creates entry for default-remapped ports. Issue #942, PR #1078.
-
getInput() failed for plugin custom types. When a node is loaded as a plugin, the
convertFromString<T>specialization defined in the plugin is not visible to the main application.getInput<T>()now uses theStringConverterstored inPortInfoinstead of callingconvertFromString<T>()directly. Issue #953, PR #1104. -
parseString now supports enums with convertFromString specializations. Issue #948, PR #1075.
-
LoopNode now accepts
std::vector<T>in addition toSharedQueue<T>. Issue #969, PR #1074. -
json:prefix handled in vectorconvertFromStringspecializations. When a port of typestd::vector<T>had a default empty value{},toStr()would produce"json:[]"which was not parsed correctly by the explicit specializations. Issue #982, PR #1073. -
JsonExporter use-after-move in vector converter registration. The
addConvertermethod movedconverterbeforevector_convertercaptured it, causingstd::bad_function_call. Issue #989, PR #1090. -
debugMessage now shows type info for remapped subtree entries. Issue #408, PR #1079.
-
DelayNode ignoring delay_msec when created from XML. PR #1097.
-
DelayNode missing
read_parameter_from_ports_initialization. PR #1103. -
Misleading static_assert when extra constructor args have wrong type. The compiler now reports that the extra arguments don't match instead of the misleading "you MUST add a constructor" message. Issue #837, PR #1098.
-
Windows build issues. Removed redundant
TINYXML2_DEBUGdefinition that caused Debug mode crashes on VS 2022 and added MSVC runtime propagation in conanfile.py. Issues #762, #869, #836, PR #1089. -
std::from_charscompilation failure on older g++ versions. PR #1110.
Improvements
-
Removed deprecated
std::aligned_storageusage. The type was deprecated in C++23 and could cause warnings in client code. PR #1061. -
Improved PreCondition documentation. Added clarifying comments about
_failureIf,_successIf,_skipIf, and_whileevaluation semantics. Issue #917. -
Generate
.clangdinPROJECT_SOURCE_DIR. This allows BT.CPP to be used as a submodule or via FetchContent/CPM without rewriting the parent project's.clangdfile. PR #1059. -
Added vcpkg installation instructions. PR #421.
-
Improved test suite quality and coverage. Added 50+ new tests covering basic types, IfThenElseNode, WhileDoElseNode, loggers, decorators, LoopNode, and reactive nodes. Tests now run faster with reduced sleep durations. PR #1102.
-
Added Doxygen welcome page with organized navigation, quick links to core classes, and complete lists of built-in nodes.