From 5dff2e537ba1aa3aac8071739f06c4e4c1f3d663 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Wed, 1 May 2024 23:20:17 +0200 Subject: [PATCH] Add `agent` parameter to `BTPlayer` to propagate upon `BehaviorTree` initialization, and add `scene_root` property to `BTTask` `scene_root` is useful to resolve exported NodePath properties in `BTTask` instances (and for BBNode parameters). --- bt/behavior_tree.cpp | 4 ++-- bt/behavior_tree.h | 2 +- bt/bt_player.cpp | 14 +++++++++++--- bt/bt_player.h | 4 ++++ bt/bt_state.cpp | 2 +- bt/tasks/bt_task.cpp | 12 ++++++++---- bt/tasks/bt_task.h | 5 ++++- bt/tasks/decorators/bt_new_scope.cpp | 4 ++-- bt/tasks/decorators/bt_new_scope.h | 2 +- bt/tasks/decorators/bt_subtree.cpp | 4 ++-- bt/tasks/decorators/bt_subtree.h | 2 +- tests/test_await_animation.h | 4 ++-- tests/test_call_method.h | 2 +- tests/test_check_agent_property.h | 2 +- tests/test_check_trigger.h | 2 +- tests/test_check_var.h | 2 +- tests/test_evaluate_expression.h | 2 +- tests/test_for_each.h | 2 +- tests/test_new_scope.h | 4 ++-- tests/test_pause_animation.h | 4 ++-- tests/test_play_animation.h | 4 ++-- tests/test_set_agent_property.h | 2 +- tests/test_set_var.h | 2 +- tests/test_stop_animation.h | 4 ++-- tests/test_subtree.h | 4 ++-- tests/test_task.h | 11 ++++++++--- util/limbo_compat.h | 2 ++ util/limbo_string_names.cpp | 2 ++ util/limbo_string_names.h | 4 ++++ 29 files changed, 73 insertions(+), 41 deletions(-) diff --git a/bt/behavior_tree.cpp b/bt/behavior_tree.cpp index 4b5e5f0..01168ff 100644 --- a/bt/behavior_tree.cpp +++ b/bt/behavior_tree.cpp @@ -71,10 +71,10 @@ void BehaviorTree::copy_other(const Ref &p_other) { root_task = p_other->get_root_task(); } -Ref BehaviorTree::instantiate(Node *p_agent, const Ref &p_blackboard) const { +Ref BehaviorTree::instantiate(Node *p_agent, const Ref &p_blackboard, Node *p_scene_root) const { ERR_FAIL_COND_V_MSG(root_task == nullptr, memnew(BTTask), "Trying to instance a behavior tree with no valid root task."); Ref inst = root_task->clone(); - inst->initialize(p_agent, p_blackboard); + inst->initialize(p_agent, p_blackboard, p_scene_root); return inst; } diff --git a/bt/behavior_tree.h b/bt/behavior_tree.h index 8935bd6..01ae806 100644 --- a/bt/behavior_tree.h +++ b/bt/behavior_tree.h @@ -53,7 +53,7 @@ public: Ref clone() const; void copy_other(const Ref &p_other); - Ref instantiate(Node *p_agent, const Ref &p_blackboard) const; + Ref instantiate(Node *p_agent, const Ref &p_blackboard, Node *p_scene_root) const; BehaviorTree(); ~BehaviorTree(); diff --git a/bt/bt_player.cpp b/bt/bt_player.cpp index 626962a..d3d3bc3 100644 --- a/bt/bt_player.cpp +++ b/bt/bt_player.cpp @@ -50,9 +50,13 @@ void BTPlayer::_load_tree() { } #endif tree_instance.unref(); - ERR_FAIL_COND_MSG(!behavior_tree.is_valid(), "BTPlayer: Needs a valid behavior tree."); - ERR_FAIL_COND_MSG(!behavior_tree->get_root_task().is_valid(), "BTPlayer: Behavior tree has no valid root task."); - tree_instance = behavior_tree->instantiate(get_owner(), blackboard); + ERR_FAIL_COND_MSG(!behavior_tree.is_valid(), "BTPlayer: Initialization failed - needs a valid behavior tree."); + ERR_FAIL_COND_MSG(!behavior_tree->get_root_task().is_valid(), "BTPlayer: Initialization failed - behavior tree has no valid root task."); + Node *agent_node = GET_NODE(this, agent); + ERR_FAIL_NULL_MSG(agent_node, vformat("BTPlayer: Initialization failed - can't get agent by provided path '%s'.", agent)); + Node *scene_root = get_owner(); + ERR_FAIL_NULL_MSG(scene_root, "BTPlayer: Initialization failed - can't get scene root (make sure the BTPlayer.owner is set)."); + tree_instance = behavior_tree->instantiate(agent_node, blackboard, scene_root); #ifdef DEBUG_ENABLED if (IS_DEBUGGER_ACTIVE()) { LimboDebugger::get_singleton()->register_bt_instance(tree_instance, get_path()); @@ -228,6 +232,8 @@ void BTPlayer::_notification(int p_notification) { void BTPlayer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_behavior_tree", "behavior_tree"), &BTPlayer::set_behavior_tree); ClassDB::bind_method(D_METHOD("get_behavior_tree"), &BTPlayer::get_behavior_tree); + ClassDB::bind_method(D_METHOD("set_agent", "agent"), &BTPlayer::set_agent); + ClassDB::bind_method(D_METHOD("get_agent"), &BTPlayer::get_agent); ClassDB::bind_method(D_METHOD("set_update_mode", "update_mode"), &BTPlayer::set_update_mode); ClassDB::bind_method(D_METHOD("get_update_mode"), &BTPlayer::get_update_mode); ClassDB::bind_method(D_METHOD("set_active", "active"), &BTPlayer::set_active); @@ -245,6 +251,7 @@ void BTPlayer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_tree_instance"), &BTPlayer::get_tree_instance); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "behavior_tree", PROPERTY_HINT_RESOURCE_TYPE, "BehaviorTree"), "set_behavior_tree", "get_behavior_tree"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "agent"), "set_agent", "get_agent"); ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "Idle,Physics,Manual"), "set_update_mode", "get_update_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "get_active"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard", PROPERTY_HINT_NONE, "Blackboard", 0), "set_blackboard", "get_blackboard"); @@ -266,6 +273,7 @@ void BTPlayer::_bind_methods() { BTPlayer::BTPlayer() { blackboard = Ref(memnew(Blackboard)); + agent = LW_NAME(node_pp); } BTPlayer::~BTPlayer() { diff --git a/bt/bt_player.h b/bt/bt_player.h index 06eec72..dffa913 100644 --- a/bt/bt_player.h +++ b/bt/bt_player.h @@ -37,6 +37,7 @@ public: private: Ref behavior_tree; + NodePath agent; Ref blackboard_plan; UpdateMode update_mode = UpdateMode::PHYSICS; bool active = true; @@ -57,6 +58,9 @@ public: void set_behavior_tree(const Ref &p_tree); Ref get_behavior_tree() const { return behavior_tree; }; + void set_agent(const NodePath &p_agent) { agent = p_agent; } + NodePath get_agent() const { return agent; } + void set_blackboard_plan(const Ref &p_plan); Ref get_blackboard_plan() const { return blackboard_plan; } diff --git a/bt/bt_state.cpp b/bt/bt_state.cpp index c03c67c..d362479 100644 --- a/bt/bt_state.cpp +++ b/bt/bt_state.cpp @@ -53,7 +53,7 @@ void BTState::_setup() { LimboState::_setup(); ERR_FAIL_COND_MSG(behavior_tree.is_null(), "BTState: BehaviorTree is not assigned."); // TODO: BBNode relies on agent to be scene owner, so if the user provides anything else, the behavior tree can break. - tree_instance = behavior_tree->instantiate(get_agent(), get_blackboard()); + tree_instance = behavior_tree->instantiate(get_agent(), get_blackboard(), get_owner()); #ifdef DEBUG_ENABLED if (tree_instance.is_valid() && IS_DEBUGGER_ACTIVE()) { diff --git a/bt/tasks/bt_task.cpp b/bt/tasks/bt_task.cpp index 66ee145..d910f99 100644 --- a/bt/tasks/bt_task.cpp +++ b/bt/tasks/bt_task.cpp @@ -159,13 +159,15 @@ void BTTask::set_custom_name(const String &p_name) { } }; -void BTTask::initialize(Node *p_agent, const Ref &p_blackboard) { - ERR_FAIL_COND(p_agent == nullptr); - ERR_FAIL_COND(p_blackboard == nullptr); +void BTTask::initialize(Node *p_agent, const Ref &p_blackboard, Node *p_scene_root) { + ERR_FAIL_NULL(p_agent); + ERR_FAIL_NULL(p_blackboard); + ERR_FAIL_NULL(p_scene_root); data.agent = p_agent; data.blackboard = p_blackboard; + data.scene_root = p_scene_root; for (int i = 0; i < data.children.size(); i++) { - get_child(i)->initialize(p_agent, p_blackboard); + get_child(i)->initialize(p_agent, p_blackboard, p_scene_root); } VCALL_OR_NATIVE(_setup); @@ -399,6 +401,7 @@ void BTTask::_bind_methods() { // Properties, setters and getters. ClassDB::bind_method(D_METHOD("get_agent"), &BTTask::get_agent); ClassDB::bind_method(D_METHOD("set_agent", "agent"), &BTTask::set_agent); + ClassDB::bind_method(D_METHOD("get_scene_root"), &BTTask::get_scene_root); ClassDB::bind_method(D_METHOD("_get_children"), &BTTask::_get_children); ClassDB::bind_method(D_METHOD("_set_children", "children"), &BTTask::_set_children); ClassDB::bind_method(D_METHOD("get_blackboard"), &BTTask::get_blackboard); @@ -410,6 +413,7 @@ void BTTask::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "custom_name"), "set_custom_name", "get_custom_name"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "agent", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "set_agent", "get_agent"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "scene_root", PROPERTY_HINT_NODE_TYPE, "Node", PROPERTY_USAGE_NONE), "", "get_scene_root"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard", PROPERTY_HINT_RESOURCE_TYPE, "Blackboard", PROPERTY_USAGE_NONE), "", "get_blackboard"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "children", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_children", "_get_children"); ADD_PROPERTY(PropertyInfo(Variant::INT, "status", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_status"); diff --git a/bt/tasks/bt_task.h b/bt/tasks/bt_task.h index 5b7a4ac..e9017ad 100644 --- a/bt/tasks/bt_task.h +++ b/bt/tasks/bt_task.h @@ -75,6 +75,7 @@ private: int index = -1; String custom_name; Node *agent = nullptr; + Node *scene_root = nullptr; Ref blackboard; BTTask *parent = nullptr; Vector> children; @@ -116,6 +117,8 @@ public: _FORCE_INLINE_ Node *get_agent() const { return data.agent; } void set_agent(Node *p_agent) { data.agent = p_agent; } + _FORCE_INLINE_ Node *get_scene_root() const { return data.scene_root; } + void set_display_collapsed(bool p_display_collapsed); bool is_displayed_collapsed() const; @@ -126,7 +129,7 @@ public: Ref get_root() const; virtual Ref clone() const; - virtual void initialize(Node *p_agent, const Ref &p_blackboard); + virtual void initialize(Node *p_agent, const Ref &p_blackboard, Node *p_scene_root); virtual PackedStringArray get_configuration_warnings(); // ! Native version. Status execute(double p_delta); diff --git a/bt/tasks/decorators/bt_new_scope.cpp b/bt/tasks/decorators/bt_new_scope.cpp index e25436e..5aaa4bc 100644 --- a/bt/tasks/decorators/bt_new_scope.cpp +++ b/bt/tasks/decorators/bt_new_scope.cpp @@ -20,7 +20,7 @@ void BTNewScope::set_blackboard_plan(const Ref &p_plan) { emit_changed(); } -void BTNewScope::initialize(Node *p_agent, const Ref &p_blackboard) { +void BTNewScope::initialize(Node *p_agent, const Ref &p_blackboard, Node *p_scene_root) { ERR_FAIL_COND(p_agent == nullptr); ERR_FAIL_COND(p_blackboard == nullptr); @@ -33,7 +33,7 @@ void BTNewScope::initialize(Node *p_agent, const Ref &p_blackboard) bb->set_parent(p_blackboard); - BTDecorator::initialize(p_agent, bb); + BTDecorator::initialize(p_agent, bb, p_scene_root); } BT::Status BTNewScope::_tick(double p_delta) { diff --git a/bt/tasks/decorators/bt_new_scope.h b/bt/tasks/decorators/bt_new_scope.h index 05226fa..a7e0020 100644 --- a/bt/tasks/decorators/bt_new_scope.h +++ b/bt/tasks/decorators/bt_new_scope.h @@ -34,7 +34,7 @@ protected: virtual Status _tick(double p_delta) override; public: - virtual void initialize(Node *p_agent, const Ref &p_blackboard) override; + virtual void initialize(Node *p_agent, const Ref &p_blackboard, Node *p_scene_root) override; }; #endif // BT_NEW_SCOPE_H diff --git a/bt/tasks/decorators/bt_subtree.cpp b/bt/tasks/decorators/bt_subtree.cpp index dfa7636..9124912 100644 --- a/bt/tasks/decorators/bt_subtree.cpp +++ b/bt/tasks/decorators/bt_subtree.cpp @@ -44,14 +44,14 @@ String BTSubtree::_generate_name() { return vformat("Subtree %s", s); } -void BTSubtree::initialize(Node *p_agent, const Ref &p_blackboard) { +void BTSubtree::initialize(Node *p_agent, const Ref &p_blackboard, Node *p_scene_root) { ERR_FAIL_COND_MSG(!subtree.is_valid(), "Subtree is not assigned."); ERR_FAIL_COND_MSG(!subtree->get_root_task().is_valid(), "Subtree root task is not valid."); ERR_FAIL_COND_MSG(get_child_count() != 0, "Subtree task shouldn't have children during initialization."); add_child(subtree->get_root_task()->clone()); - BTNewScope::initialize(p_agent, p_blackboard); + BTNewScope::initialize(p_agent, p_blackboard, p_scene_root); } BT::Status BTSubtree::_tick(double p_delta) { diff --git a/bt/tasks/decorators/bt_subtree.h b/bt/tasks/decorators/bt_subtree.h index b248df7..b97504a 100644 --- a/bt/tasks/decorators/bt_subtree.h +++ b/bt/tasks/decorators/bt_subtree.h @@ -35,7 +35,7 @@ public: void set_subtree(const Ref &p_value); Ref get_subtree() const { return subtree; } - virtual void initialize(Node *p_agent, const Ref &p_blackboard) override; + virtual void initialize(Node *p_agent, const Ref &p_blackboard, Node *p_scene_root) override; virtual PackedStringArray get_configuration_warnings() override; BTSubtree() = default; diff --git a/tests/test_await_animation.h b/tests/test_await_animation.h index 4f949f3..06c4f52 100644 --- a/tests/test_await_animation.h +++ b/tests/test_await_animation.h @@ -51,13 +51,13 @@ TEST_CASE("[SceneTree][LimboAI] BTAwaitAnimation") { SUBCASE("When AnimationPlayer doesn't exist") { player_param->set_saved_value(NodePath("./NotFound")); ERR_PRINT_OFF; - awa->initialize(dummy, bb); + awa->initialize(dummy, bb, dummy); CHECK(awa->execute(0.01666) == BTTask::FAILURE); ERR_PRINT_ON; } SUBCASE("When AnimationPlayer exists") { player_param->set_saved_value(player->get_path()); - awa->initialize(dummy, bb); + awa->initialize(dummy, bb, dummy); SUBCASE("When AnimationPlayer is not playing") { REQUIRE_FALSE(player->is_playing()); diff --git a/tests/test_call_method.h b/tests/test_call_method.h index 711908a..3dd7324 100644 --- a/tests/test_call_method.h +++ b/tests/test_call_method.h @@ -47,7 +47,7 @@ TEST_CASE("[Modules][LimboAI] BTCallMethod") { node_param->set_variable("object"); cm->set_method("callback"); - cm->initialize(dummy, bb); + cm->initialize(dummy, bb, dummy); SUBCASE("When method is empty") { cm->set_method(""); diff --git a/tests/test_check_agent_property.h b/tests/test_check_agent_property.h index 3465bad..88c0cb4 100644 --- a/tests/test_check_agent_property.h +++ b/tests/test_check_agent_property.h @@ -39,7 +39,7 @@ TEST_CASE("[Modules][LimboAI] BTCheckAgentProperty") { Ref cap = memnew(BTCheckAgentProperty); Node *agent = memnew(Node); Ref bb = memnew(Blackboard); - cap->initialize(agent, bb); + cap->initialize(agent, bb, agent); StringName agent_name = "SimpleNode"; agent->set_name(agent_name); diff --git a/tests/test_check_trigger.h b/tests/test_check_trigger.h index af490af..0f4307a 100644 --- a/tests/test_check_trigger.h +++ b/tests/test_check_trigger.h @@ -24,7 +24,7 @@ TEST_CASE("[Modules][LimboAI] BTCheckTrigger") { Node *dummy = memnew(Node); Ref bb = memnew(Blackboard); - ct->initialize(dummy, bb); + ct->initialize(dummy, bb, dummy); SUBCASE("Empty") { ERR_PRINT_OFF; diff --git a/tests/test_check_var.h b/tests/test_check_var.h index 1406837..4bc1f9c 100644 --- a/tests/test_check_var.h +++ b/tests/test_check_var.h @@ -36,7 +36,7 @@ TEST_CASE("[Modules][LimboAI] BTCheckVar") { Ref cv = memnew(BTCheckVar); Ref bb = memnew(Blackboard); Node *dummy = memnew(Node); - cv->initialize(dummy, bb); + cv->initialize(dummy, bb, dummy); SUBCASE("Check with empty variable and value") { cv->set_variable(""); diff --git a/tests/test_evaluate_expression.h b/tests/test_evaluate_expression.h index 58d4ca5..15702c7 100644 --- a/tests/test_evaluate_expression.h +++ b/tests/test_evaluate_expression.h @@ -47,7 +47,7 @@ TEST_CASE("[Modules][LimboAI] BTEvaluateExpression") { node_param->set_variable("object"); ee->set_expression_string("callback()"); - ee->initialize(dummy, bb); + ee->initialize(dummy, bb, dummy); SUBCASE("When expression string is empty") { ee->set_expression_string(""); diff --git a/tests/test_for_each.h b/tests/test_for_each.h index 0ab4919..00cad30 100644 --- a/tests/test_for_each.h +++ b/tests/test_for_each.h @@ -23,7 +23,7 @@ TEST_CASE("[Modules][LimboAI] BTForEach") { Ref fe = memnew(BTForEach); Node *dummy = memnew(Node); Ref blackboard = memnew(Blackboard); - fe->initialize(dummy, blackboard); + fe->initialize(dummy, blackboard, dummy); Array arr; arr.append("apple"); diff --git a/tests/test_new_scope.h b/tests/test_new_scope.h index 988edd7..c5627b7 100644 --- a/tests/test_new_scope.h +++ b/tests/test_new_scope.h @@ -26,7 +26,7 @@ TEST_CASE("[Modules][LimboAI] BTNewScope") { SUBCASE("When empty") { ERR_PRINT_OFF; - ns->initialize(dummy, parent_bb); + ns->initialize(dummy, parent_bb, dummy); CHECK(ns->execute(0.01666) == BTTask::FAILURE); ERR_PRINT_ON; } @@ -45,7 +45,7 @@ TEST_CASE("[Modules][LimboAI] BTNewScope") { REQUIRE(parent_bb->has_var("vegetable")); REQUIRE(parent_bb->get_var("vegetable", "wetgoop") == "carrot"); - parent->initialize(dummy, parent_bb); + parent->initialize(dummy, parent_bb, dummy); CHECK(ns->get_blackboard() != parent->get_blackboard()); CHECK(ns->get_blackboard() == child->get_blackboard()); diff --git a/tests/test_pause_animation.h b/tests/test_pause_animation.h index a438068..8f7e3fb 100644 --- a/tests/test_pause_animation.h +++ b/tests/test_pause_animation.h @@ -48,13 +48,13 @@ TEST_CASE("[SceneTree][LimboAI] BTPauseAnimation") { SUBCASE("When AnimationPlayer doesn't exist") { player_param->set_saved_value(NodePath("./NotFound")); ERR_PRINT_OFF; - pa->initialize(dummy, bb); + pa->initialize(dummy, bb, dummy); CHECK(pa->execute(0.01666) == BTTask::FAILURE); ERR_PRINT_ON; } SUBCASE("When AnimationPlayer exists") { player_param->set_saved_value(player->get_path()); - pa->initialize(dummy, bb); + pa->initialize(dummy, bb, dummy); SUBCASE("When AnimationPlayer is not playing") { REQUIRE_FALSE(player->is_playing()); diff --git a/tests/test_play_animation.h b/tests/test_play_animation.h index 245ee74..85c71ec 100644 --- a/tests/test_play_animation.h +++ b/tests/test_play_animation.h @@ -49,13 +49,13 @@ TEST_CASE("[SceneTree][LimboAI] BTPlayAnimation") { SUBCASE("When AnimationPlayer doesn't exist") { player_param->set_saved_value(NodePath("./NotFound")); ERR_PRINT_OFF; - pa->initialize(dummy, bb); + pa->initialize(dummy, bb, dummy); CHECK(pa->execute(0.01666) == BTTask::FAILURE); ERR_PRINT_ON; } SUBCASE("When AnimationPlayer exists") { player_param->set_saved_value(player->get_path()); - pa->initialize(dummy, bb); + pa->initialize(dummy, bb, dummy); SUBCASE("When not waiting to finish") { pa->set_await_completion(0.0); diff --git a/tests/test_set_agent_property.h b/tests/test_set_agent_property.h index bb84e18..50f84b4 100644 --- a/tests/test_set_agent_property.h +++ b/tests/test_set_agent_property.h @@ -28,7 +28,7 @@ TEST_CASE("[Modules][LimboAI] BTSetAgentProperty") { Ref sap = memnew(BTSetAgentProperty); Node *agent = memnew(Node); Ref bb = memnew(Blackboard); - sap->initialize(agent, bb); + sap->initialize(agent, bb, agent); sap->set_property("process_priority"); // * property that will be set by the task Ref value = memnew(BBVariant); diff --git a/tests/test_set_var.h b/tests/test_set_var.h index 51f2c1f..da214e2 100644 --- a/tests/test_set_var.h +++ b/tests/test_set_var.h @@ -29,7 +29,7 @@ TEST_CASE("[Modules][LimboAI] BTSetVar") { Ref bb = memnew(Blackboard); Node *dummy = memnew(Node); - sv->initialize(dummy, bb); + sv->initialize(dummy, bb, dummy); SUBCASE("When variable is not set") { ERR_PRINT_OFF; diff --git a/tests/test_stop_animation.h b/tests/test_stop_animation.h index 1ffb960..1313761 100644 --- a/tests/test_stop_animation.h +++ b/tests/test_stop_animation.h @@ -48,13 +48,13 @@ TEST_CASE("[SceneTree][LimboAI] BTStopAnimation") { SUBCASE("When AnimationPlayer doesn't exist") { player_param->set_saved_value(NodePath("./NotFound")); ERR_PRINT_OFF; - sa->initialize(dummy, bb); + sa->initialize(dummy, bb, dummy); CHECK(sa->execute(0.01666) == BTTask::FAILURE); ERR_PRINT_ON; } SUBCASE("When AnimationPlayer exists") { player_param->set_saved_value(player->get_path()); - sa->initialize(dummy, bb); + sa->initialize(dummy, bb, dummy); SUBCASE("When AnimationPlayer is not playing") { REQUIRE_FALSE(player->is_playing()); diff --git a/tests/test_subtree.h b/tests/test_subtree.h index ebaa4bc..a5e5204 100644 --- a/tests/test_subtree.h +++ b/tests/test_subtree.h @@ -29,7 +29,7 @@ TEST_CASE("[Modules][LimboAI] BTSubtree") { SUBCASE("When empty") { ERR_PRINT_OFF; - st->initialize(dummy, bb); + st->initialize(dummy, bb, dummy); CHECK(st->execute(0.01666) == BTTask::FAILURE); ERR_PRINT_ON; } @@ -41,7 +41,7 @@ TEST_CASE("[Modules][LimboAI] BTSubtree") { st->set_subtree(bt); CHECK(st->get_child_count() == 0); - st->initialize(dummy, bb); + st->initialize(dummy, bb, dummy); CHECK(st->get_child_count() == 1); CHECK(st->get_child(0) != task); diff --git a/tests/test_task.h b/tests/test_task.h index 1d1e71d..5e79ae0 100644 --- a/tests/test_task.h +++ b/tests/test_task.h @@ -162,7 +162,7 @@ TEST_CASE("[Modules][LimboAI] BTTask") { Node *dummy = memnew(Node); Ref bb = memnew(Blackboard); SUBCASE("With valid parameters") { - task->initialize(dummy, bb); + task->initialize(dummy, bb, dummy); CHECK(task->get_agent() == dummy); CHECK(task->get_blackboard() == bb); CHECK(child1->get_agent() == dummy); @@ -174,12 +174,17 @@ TEST_CASE("[Modules][LimboAI] BTTask") { } SUBCASE("Test if not crashes when agent is null") { ERR_PRINT_OFF; - task->initialize(nullptr, bb); + task->initialize(nullptr, bb, dummy); + ERR_PRINT_ON; + } + SUBCASE("Test if not crashes when scene_owner is null") { + ERR_PRINT_OFF; + task->initialize(dummy, bb, nullptr); ERR_PRINT_ON; } SUBCASE("Test if not crashes when BB is null") { ERR_PRINT_OFF; - task->initialize(dummy, nullptr); + task->initialize(dummy, nullptr, dummy); ERR_PRINT_ON; } memdelete(dummy); diff --git a/util/limbo_compat.h b/util/limbo_compat.h index 321dc40..228cb3e 100644 --- a/util/limbo_compat.h +++ b/util/limbo_compat.h @@ -53,6 +53,7 @@ #define PERFORMANCE_ADD_CUSTOM_MONITOR(m_id, m_callable) (Performance::get_singleton()->add_custom_monitor(m_id, m_callable, Variant())) #define GET_SCRIPT(m_obj) (m_obj->get_script_instance() ? m_obj->get_script_instance()->get_script() : nullptr) #define ADD_STYLEBOX_OVERRIDE(m_control, m_name, m_stylebox) (m_control->add_theme_style_override(m_name, m_stylebox)) +#define GET_NODE(m_parent, m_path) m_parent->get_node(m_path) _FORCE_INLINE_ bool OBJECT_HAS_PROPERTY(Object *p_obj, const StringName &p_prop) { bool r_valid; @@ -137,6 +138,7 @@ using namespace godot; #define PERFORMANCE_ADD_CUSTOM_MONITOR(m_id, m_callable) (Performance::get_singleton()->add_custom_monitor(m_id, m_callable)) #define GET_SCRIPT(m_obj) (m_obj->get_script()) #define ADD_STYLEBOX_OVERRIDE(m_control, m_name, m_stylebox) (m_control->add_theme_stylebox_override(m_name, m_stylebox)) +#define GET_NODE(m_parent, m_path) m_parent->get_node_internal(m_path) _FORCE_INLINE_ bool OBJECT_HAS_PROPERTY(Object *p_obj, const StringName &p_prop) { return Variant(p_obj).has_key(p_prop); diff --git a/util/limbo_string_names.cpp b/util/limbo_string_names.cpp index 0f1dd67..a223ded 100644 --- a/util/limbo_string_names.cpp +++ b/util/limbo_string_names.cpp @@ -166,4 +166,6 @@ LimboStringNames::LimboStringNames() { repeat_forever.parse_utf8("Repeat ∞"); output_var_prefix.parse_utf8("➜"); + + node_pp = NodePath(".."); } diff --git a/util/limbo_string_names.h b/util/limbo_string_names.h index fe62c27..10e6542 100644 --- a/util/limbo_string_names.h +++ b/util/limbo_string_names.h @@ -13,6 +13,7 @@ #define LIMBO_STRING_NAMES_H #ifdef LIMBOAI_MODULE +#include "core/string/node_path.h" #include "core/string/string_name.h" #include "core/typedefs.h" #include "modules/register_module_types.h" @@ -20,6 +21,7 @@ #ifdef LIMBOAI_GDEXTENSION #include "godot_cpp/variant/string.hpp" +#include #include using namespace godot; #endif // LIMBOAI_GDEXTENSION @@ -181,6 +183,8 @@ public: String repeat_forever; String output_var_prefix; + + NodePath node_pp; }; #define LW_NAME(m_arg) LimboStringNames::get_singleton()->m_arg