Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Add optional metadata to TreeNodeManifest #730

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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());
}