Skip to content

Commit 6229135

Browse files
committed
Fix #942: getLockedPortContent creates entry for default-remapped ports
1 parent fd40532 commit 6229135

File tree

2 files changed

+76
-1
lines changed

2 files changed

+76
-1
lines changed

src/tree_node.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,21 @@ AnyPtrLocked BT::TreeNode::getLockedPortContent(const std::string& key)
479479
{
480480
if(auto remapped_key = getRemappedKey(key, getRawPortValue(key)))
481481
{
482-
return _p->config.blackboard->getAnyLocked(std::string(*remapped_key));
482+
const auto bb_key = std::string(*remapped_key);
483+
auto result = _p->config.blackboard->getAnyLocked(bb_key);
484+
if(!result && _p->config.manifest)
485+
{
486+
// Entry doesn't exist yet. Create it using the port's type info
487+
// from the manifest so that getLockedPortContent works even when
488+
// the port is not explicitly declared in XML. Issue #942.
489+
auto port_it = _p->config.manifest->ports.find(key);
490+
if(port_it != _p->config.manifest->ports.end())
491+
{
492+
_p->config.blackboard->createEntry(bb_key, port_it->second);
493+
result = _p->config.blackboard->getAnyLocked(bb_key);
494+
}
495+
}
496+
return result;
483497
}
484498
return {};
485499
}

tests/gtest_blackboard.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,3 +773,64 @@ TEST(BlackboardTest, DebugMessageShowsRemappedEntries_Issue408)
773773
"entry. Got: "
774774
<< output;
775775
}
776+
777+
// Issue #942: getLockedPortContent should return a valid locked reference
778+
// even when the port is not explicitly declared in XML, as long as there is
779+
// a default blackboard remapping (e.g., "{=}").
780+
class ActionWithLockedPort : public SyncActionNode
781+
{
782+
public:
783+
ActionWithLockedPort(const std::string& name, const NodeConfig& config)
784+
: SyncActionNode(name, config)
785+
{}
786+
787+
NodeStatus tick() override
788+
{
789+
auto any_locked = getLockedPortContent("value");
790+
if(!any_locked)
791+
{
792+
locked_valid = false;
793+
return NodeStatus::FAILURE;
794+
}
795+
locked_valid = true;
796+
// Assign a value through the locked reference
797+
any_locked.assign(42);
798+
return NodeStatus::SUCCESS;
799+
}
800+
801+
static PortsList providedPorts()
802+
{
803+
return { BidirectionalPort<int>("value", "{=}", "A value with default BB remap") };
804+
}
805+
806+
bool locked_valid = false;
807+
};
808+
809+
TEST(BlackboardTest, GetLockedPortContentWithDefault_Issue942)
810+
{
811+
// XML does NOT specify the "value" port — relies on default "{=}"
812+
std::string xml_txt = R"(
813+
<root BTCPP_format="4" >
814+
<BehaviorTree ID="Main">
815+
<ActionWithLockedPort/>
816+
</BehaviorTree>
817+
</root>)";
818+
819+
BehaviorTreeFactory factory;
820+
factory.registerNodeType<ActionWithLockedPort>("ActionWithLockedPort");
821+
auto tree = factory.createTreeFromText(xml_txt);
822+
auto status = tree.tickWhileRunning();
823+
824+
ASSERT_EQ(status, NodeStatus::SUCCESS);
825+
826+
for(const auto& node : tree.subtrees.front()->nodes)
827+
{
828+
if(auto action = dynamic_cast<ActionWithLockedPort*>(node.get()))
829+
{
830+
ASSERT_TRUE(action->locked_valid);
831+
}
832+
}
833+
834+
// The value should be accessible from the blackboard
835+
ASSERT_EQ(tree.rootBlackboard()->get<int>("value"), 42);
836+
}

0 commit comments

Comments
 (0)