Skip to content

Commit

Permalink
Merge pull request #730 from adlarkin/add_metadata
Browse files Browse the repository at this point in the history
Add optional metadata to TreeNodeManifest
  • Loading branch information
facontidavide authored Jan 10, 2024
2 parents db5789e + 96910f2 commit 994650d
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 33 deletions.
9 changes: 5 additions & 4 deletions include/behaviortree_cpp/basic_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
#include <chrono>
#include <memory>
#include <string_view>
#include <utility>
#include <variant>
#include <vector>
#include <optional>

#include "behaviortree_cpp/utils/safe_any.hpp"
Expand Down Expand Up @@ -438,14 +440,14 @@ struct has_static_method_providedPorts<
};

template <typename T, typename = void>
struct has_static_method_description : std::false_type
struct has_static_method_metadata : std::false_type
{
};

template <typename T>
struct has_static_method_description<
struct has_static_method_metadata<
T, typename std::enable_if<
std::is_same<decltype(T::description()), std::string>::value>::type>
std::is_same<decltype(T::metadata()), std::vector<std::pair<std::string, std::string>>>::value>::type>
: std::true_type
{
};
Expand All @@ -467,4 +469,3 @@ using TimePoint = std::chrono::high_resolution_clock::time_point;
using Duration = std::chrono::high_resolution_clock::duration;

} // namespace BT

16 changes: 8 additions & 8 deletions include/behaviortree_cpp/bt_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <utility>
#include <vector>

#include "behaviortree_cpp/contrib/magic_enum.hpp"
#include "behaviortree_cpp/behavior_tree.h"
Expand All @@ -44,13 +46,11 @@ template <typename T>
inline TreeNodeManifest CreateManifest(const std::string& ID,
PortsList portlist = getProvidedPorts<T>())
{
if constexpr( has_static_method_description<T>::value)
if constexpr( has_static_method_metadata<T>::value )
{
return {getType<T>(), ID, portlist, T::description()};
}
else {
return {getType<T>(), ID, portlist, {}};
return {getType<T>(), ID, portlist, T::metadata()};
}
return {getType<T>(), ID, portlist, {}};
}

#ifdef BT_PLUGIN_EXPORT
Expand Down Expand Up @@ -425,10 +425,10 @@ class BehaviorTreeFactory
Tree createTree(const std::string& tree_name,
Blackboard::Ptr blackboard = Blackboard::create());

/// Add a description to a specific manifest. This description will be added
/// Add metadata to a specific manifest. This metadata will be added
/// to <TreeNodesModel> with the function writeTreeNodesModelXML()
void addDescriptionToManifest(const std::string& node_id,
const std::string& description);
void addMetadataToManifest(const std::string& node_id,
const std::vector<std::pair<std::string, std::string>>& metadata);

/**
* @brief Add an Enum to the scripting language.
Expand Down
4 changes: 3 additions & 1 deletion include/behaviortree_cpp/tree_node.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#include <exception>
#include <mutex>
#include <map>
#include <utility>
#include <vector>

#include "behaviortree_cpp/utils/signal.h"
#include "behaviortree_cpp/basic_types.h"
Expand All @@ -38,7 +40,7 @@ struct TreeNodeManifest
NodeType type;
std::string registration_ID;
PortsList ports;
std::string description;
std::vector<std::pair<std::string, std::string>> metadata;
};

using PortsRemapping = std::unordered_map<std::string, std::string>;
Expand Down
10 changes: 5 additions & 5 deletions src/bt_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ BehaviorTreeFactory::BehaviorTreeFactory():
registerNodeType<SwitchNode<4>>("Switch4");
registerNodeType<SwitchNode<5>>("Switch5");
registerNodeType<SwitchNode<6>>("Switch6");

registerNodeType<LoopNode<int>>("LoopInt");
registerNodeType<LoopNode<bool>>("LoopBool");
registerNodeType<LoopNode<double>>("LoopDouble");
Expand Down Expand Up @@ -435,15 +435,15 @@ Tree BehaviorTreeFactory::createTree(const std::string& tree_name,
return tree;
}

void BehaviorTreeFactory::addDescriptionToManifest(const std::string& node_id,
const std::string& description)
void BehaviorTreeFactory::addMetadataToManifest(const std::string& node_id,
const std::vector<std::pair<std::string, std::string>>& metadata)
{
auto it = _p->manifests.find(node_id);
if (it == _p->manifests.end())
{
throw std::runtime_error("addDescriptionToManifest: wrong ID");
throw std::runtime_error("addMetadataToManifest: wrong ID");
}
it->second.description = description;
it->second.metadata = metadata;
}

void BehaviorTreeFactory::registerScriptingEnum(StringView name, int value)
Expand Down
19 changes: 13 additions & 6 deletions src/xml_parsing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ struct XMLParser::PImpl
std::map<std::string, SubtreeModel> subtree_models;

int suffix_count;

explicit PImpl(const BehaviorTreeFactory& fact) :
factory(fact), current_path(std::filesystem::current_path()), suffix_count(0)
{}
Expand Down Expand Up @@ -982,11 +982,18 @@ void addNodeModelToXML(const TreeNodeManifest& model,
element->InsertEndChild(port_element);
}

if (!model.description.empty())
if (!model.metadata.empty())
{
auto description_element = doc.NewElement("description");
description_element->SetText(model.description.c_str());
element->InsertEndChild(description_element);
auto metadata_root = doc.NewElement("MetadataFields");

for (const auto& [name, value] : model.metadata)
{
auto metadata_element = doc.NewElement("Metadata");
metadata_element->SetAttribute(name.c_str(), value.c_str());
metadata_root->InsertEndChild(metadata_element);
}

element->InsertEndChild(metadata_root);
}

model_root->InsertEndChild(element);
Expand All @@ -997,7 +1004,7 @@ void addTreeToXML(const Tree& tree,
XMLElement* rootXML,
bool add_metadata,
bool add_builtin_models)
{
{
std::function<void(const TreeNode&, XMLElement*)> addNode;
addNode = [&](const TreeNode& node,
XMLElement* parent_elem)
Expand Down
47 changes: 38 additions & 9 deletions tests/gtest_factory.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#include <gtest/gtest.h>
#include <filesystem>
#include <string>
#include <utility>
#include <vector>
#include "behaviortree_cpp/xml_parsing.h"
#include "../sample_nodes/crossdoor_nodes.h"
#include "../sample_nodes/dummy_nodes.h"
Expand Down Expand Up @@ -388,10 +391,18 @@ TEST(BehaviorTreeReload, ReloadSameTree)
}
}

class DescriptiveAction : public SyncActionNode
std::vector<std::pair<std::string, std::string>> makeTestMetadata()
{
return {
std::make_pair<std::string, std::string>("foo", "hello"),
std::make_pair<std::string, std::string>("bar", "42"),
};
}

class ActionWithMetadata : public SyncActionNode
{
public:
DescriptiveAction(const std::string& name, const NodeConfig& config):
ActionWithMetadata(const std::string& name, const NodeConfig& config):
SyncActionNode(name, config) {}

BT::NodeStatus tick() override {
Expand All @@ -402,21 +413,39 @@ class DescriptiveAction : public SyncActionNode
return {};
}

static std::string description() {
return "THE DESCRIPTION";
static std::vector<std::pair<std::string, std::string>> metadata() {
return makeTestMetadata();
}
};

TEST(BehaviorTreeFactory, DescriptionMethod)
TEST(BehaviorTreeFactory, ManifestMethod)
{
const char* expectedXML = R"(
<Action ID="ActionWithMetadata">
<MetadataFields>
<Metadata foo="hello"/>
<Metadata bar="42"/>
</MetadataFields>
</Action>)";

BehaviorTreeFactory factory;
factory.registerNodeType<DescriptiveAction>("DescriptiveAction");
const auto& manifest = factory.manifests().at("DescriptiveAction");
ASSERT_EQ(manifest.description, "THE DESCRIPTION");
factory.registerNodeType<ActionWithMetadata>("ActionWithMetadata");
const auto& manifest = factory.manifests().at("ActionWithMetadata");
EXPECT_EQ(manifest.metadata, makeTestMetadata());

auto xml = writeTreeNodesModelXML(factory, false);
std::cout << xml << std::endl;

ASSERT_NE(xml.find( "<description>THE DESCRIPTION</description>"), std::string::npos);
EXPECT_NE(xml.find(expectedXML), std::string::npos);
}

TEST(BehaviorTreeFactory, addMetadataToManifest)
{
BehaviorTreeFactory factory;
factory.registerNodeType<DummyNodes::SaySomething>("SaySomething");
const auto& initial_manifest = factory.manifests().at("SaySomething");
EXPECT_TRUE(initial_manifest.metadata.empty());
factory.addMetadataToManifest("SaySomething", makeTestMetadata());
const auto& modified_manifest = factory.manifests().at("SaySomething");
EXPECT_EQ(modified_manifest.metadata, makeTestMetadata());
}

0 comments on commit 994650d

Please sign in to comment.