23#include "auto_apms_behavior_tree_core/builder.hpp"
24#include "auto_apms_behavior_tree_core/node/node_manifest.hpp"
25#include "auto_apms_util/container.hpp"
26#include "auto_apms_util/string.hpp"
27#include "behaviortree_cpp/xml_parsing.h"
31const std::regex no_typed_setter_getter_types(
32 "std::shared_ptr|std::unique_ptr|std::weak_ptr|BT::Any|BT::AnyTypeAllowed|std::string");
33const std::vector<BT::NodeType> leaf_node_types{BT::NodeType::ACTION, BT::NodeType::SUBTREE};
35int main(
int argc,
char ** argv)
37 bool include_native_nodes =
false;
39 std::cerr <<
"create_node_model_header: Missing inputs! The program requires: \n\t1.) The path to the node plugin "
40 "manifest YAML file.\n\t2.) The path to the nodes model XML file.\n\t3.) The name of the package "
41 "building the node model header.\n\t4.) The path of the output .hpp file.\n";
42 std::cerr <<
"Usage: create_node_model_header <manifest_file> <model_file> <build_package_name> <header_path>.\n";
47 const std::filesystem::path manifest_file = std::filesystem::absolute(argv[1]);
48 const std::filesystem::path model_file = std::filesystem::absolute(argv[2]);
51 if (build_package_name ==
"auto_apms_behavior_tree") include_native_nodes =
true;
54 if (manifest_file.empty()) {
55 throw std::runtime_error(
"Argument manifest_file must not be empty.");
57 if (model_file.empty()) {
58 throw std::runtime_error(
"Argument model_file must not be empty.");
60 if (header_path.empty()) {
61 throw std::runtime_error(
"Argument header_path must not be empty.");
65 if (header_path.extension() !=
".hpp") {
66 throw std::runtime_error(
"Output file '" + header_path.string() +
"' has wrong extension. Must be '.hpp'.");
70 tinyxml2::XMLDocument model_doc;
73 const std::set<std::string> native_node_names = BT::BehaviorTreeFactory().builtinNodes();
74 if (include_native_nodes) {
76 model_doc.Parse(BT::writeTreeNodesModelXML(BT::BehaviorTreeFactory(),
true).c_str()) !=
77 tinyxml2::XMLError::XML_SUCCESS) {
78 throw std::runtime_error(model_doc.ErrorStr());
81 for (
const auto & [name, _] : model_map) {
84 manifest.
add(name, opt);
86 manifest.
remove(core::TreeDocument::SUBTREE_ELEMENT_NAME);
90 manifest.
merge(core::NodeManifest::fromFile(manifest_file));
91 if (model_doc.LoadFile(model_file.c_str()) != tinyxml2::XMLError::XML_SUCCESS) {
92 throw std::runtime_error(model_doc.ErrorStr());
97 std::ostringstream content;
98 content << R
"(// This header has been generated automatically. DO NOT CHANGE!
102#include "behaviortree_cpp/basic_types.h"
103#include "auto_apms_behavior_tree_core/convert.hpp"
104#include "auto_apms_behavior_tree_core/node/node_model_type.hpp"
106namespace )" << build_package_name << R"(::model
110 for (
const auto & [node_name, options] : manifest.
map()) {
111 NodeModelMap::const_iterator it = model_map.find(node_name);
112 if (it == model_map.end())
continue;
114 const bool is_native_node = native_node_names.find(node_name) != native_node_names.end();
116 const std::string base_class_name = is_leaf ?
"LeafNodeModelType" :
"NodeModelType";
120class )" << node_name << R
"( : public auto_apms_behavior_tree::core::)" << base_class_name << R"(
122friend class auto_apms_behavior_tree::core::TreeDocument::NodeElement;
124using )" << base_class_name << "::" << base_class_name << R
"(;
128static PortInfos ports()
135 content <<
"port_infos[\"" << info.
port_name <<
"\"].setDefaultValue(BT::convertFromString<" << info.
port_type <<
">(\"" << info.
port_default <<
"\"));\n";
138 content << R
"(return port_infos;
142static BT::NodeType type()
144return BT::convertFromString<BT::NodeType>(")" <<
model.type << R
"(");
148static std::string name()
150return ")" << node_name << R
"(";
154std::string getRegistrationName() const override final
160 if (!is_native_node) {
161 content << R
"(/// @brief Registration options for this node.
162static RegistrationOptions registrationOptions()
164return RegistrationOptions::decode(R"()" << options.encode() << ")\");" << R
"(
170 content <<
"AUTO_APMS_BEHAVIOR_TREE_CORE_DEFINE_NON_LEAF_THISREF_METHODS(" << node_name <<
")\n";
172 content <<
"AUTO_APMS_BEHAVIOR_TREE_CORE_DEFINE_LEAF_THISREF_METHODS(" << node_name <<
")\n";
178)" << node_name <<
" & set_" << info.
port_name <<
"(const std::string & str";
186return setPorts({{")" << info.port_name << R"(", str}});
192const std::string & get_)" << info.
port_name << R
"(_str() const
194return getPorts().at(")" << info.port_name << R"(");
197 if (std::regex_search(info.
port_type, no_typed_setter_getter_types))
continue;
202)" << node_name <<
" & set_" << info.
port_name <<
"(const " << info.
port_type <<
" & val)" << R
"(
204return setPorts({{")" << info.port_name << R"(", BT::toStr(val)}});
212return BT::convertFromString<)" << info.port_type << ">(get_" << info.
port_name << R
"(_str());
221 std::ofstream out_stream(header_path);
222 if (out_stream.is_open()) {
223 out_stream << content.str();
226 throw std::runtime_error(
"Error opening node model header file '" + header_path.string() +
"'");
228 }
catch (
const std::exception & e) {
229 std::cerr <<
"ERROR (create_node_model_header): " << e.what() <<
"\n";
Data structure for information about which behavior tree node plugin to load and how to configure the...
NodeManifest & add(const std::string &node_name, const RegistrationOptions &opt)
Add registration options for a behavior tree node to the manifest.
NodeManifest & merge(const NodeManifest &other, bool replace=false)
Merges another NodeManifest with this one.
const Map & map() const
Get a view of the internal map.
NodeManifest & remove(const std::string &node_name)
Remove registration options for a behavior tree node.
static NodeModelMap getNodeModel(tinyxml2::XMLDocument &doc, const NodeManifest &manifest)
Convert a behavior tree node model document to the corresponding data structure.
std::string trimWhitespaces(const std::string &str)
Trim whitespaces from both ends of a string.
bool contains(const ContainerT< ValueT, AllocatorT > &c, const ValueT &val)
Check whether a particular container structure contains a value.
Models for all available behavior tree nodes.
Powerful tooling for incorporating behavior trees for task development.
std::map< std::string, NodeModel > NodeModelMap
Mapping of node registration names and their implementation details.
Data structure encapsulating the information of all ports implemented by a behavior tree node.
Implementation details of a single data port.
std::string port_default
Default value of the port encoded as string.
bool port_has_default
Flag whether the port implements a default value or not.
std::string port_description
Description of the port.
BT::PortDirection port_direction
Direction of the port.
std::string port_type
String representation of the C++ type given to the port.
std::string port_name
Name of the port.
Parameters for loading and registering a behavior tree node class from a shared library using e....
std::string class_name
Fully qualified name of the behavior tree node plugin class.