From bdfe5f52c21ea02b32f93092f8ed45fae2c2af57 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Mon, 13 May 2024 23:21:55 +0200 Subject: [PATCH 01/20] BlackboardPlan: Implement rudimentary mapping --- blackboard/blackboard_plan.cpp | 61 +++++++++++++++++++++++++++++----- blackboard/blackboard_plan.h | 11 +++++- 2 files changed, 63 insertions(+), 9 deletions(-) diff --git a/blackboard/blackboard_plan.cpp b/blackboard/blackboard_plan.cpp index d55cd03..f9c97ec 100644 --- a/blackboard/blackboard_plan.cpp +++ b/blackboard/blackboard_plan.cpp @@ -24,6 +24,12 @@ bool BlackboardPlan::_set(const StringName &p_name, const Variant &p_value) { } return true; } + if (name_str.begins_with("_mapping_")) { + StringName mapped_var_name = name_str.trim_prefix("_mapping_"); + ERR_FAIL_COND_V(!has_var(mapped_var_name), false); + parent_scope_mapping[mapped_var_name] = p_value; + return true; + } // * Storage if (name_str.begins_with("var/")) { @@ -56,7 +62,20 @@ bool BlackboardPlan::_get(const StringName &p_name, Variant &r_ret) const { // * Editor if (var_map.has(p_name)) { - r_ret = var_map[p_name].get_value(); + if (has_mapping(p_name)) { + r_ret = "Mapped to $" + parent_scope_mapping[p_name]; + } else { + r_ret = var_map[p_name].get_value(); + } + return true; + } + if (name_str.begins_with("_mapping_")) { + String mapped_var_name = name_str.trim_prefix("_mapping_"); + if (parent_scope_mapping.has(mapped_var_name)) { + r_ret = parent_scope_mapping[mapped_var_name]; + } else { + r_ret = StringName(); + } return true; } @@ -90,22 +109,33 @@ void BlackboardPlan::_get_property_list(List *p_list) const { // * Editor if (var.get_type() != Variant::NIL && (!is_derived() || !var_name.begins_with("_"))) { - p_list->push_back(PropertyInfo(var.get_type(), var_name, var.get_hint(), var.get_hint_string(), PROPERTY_USAGE_EDITOR)); + if (has_mapping(var_name)) { + p_list->push_back(PropertyInfo(Variant::STRING, var_name, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_READ_ONLY)); + } else { + p_list->push_back(PropertyInfo(var.get_type(), var_name, var.get_hint(), var.get_hint_string(), PROPERTY_USAGE_EDITOR)); + } } + // * Storage if (is_derived() && (!var.is_value_changed() || var.get_value() == base->var_map[var_name].get_value())) { // Don't store variable if it's not modified in a derived plan. // Variable is considered modified when it's marked as changed and its value is different from the base plan. continue; } - - // * Storage p_list->push_back(PropertyInfo(Variant::STRING, "var/" + var_name + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); p_list->push_back(PropertyInfo(Variant::INT, "var/" + var_name + "/type", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); p_list->push_back(PropertyInfo(var.get_type(), "var/" + var_name + "/value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); p_list->push_back(PropertyInfo(Variant::INT, "var/" + var_name + "/hint", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); p_list->push_back(PropertyInfo(Variant::STRING, "var/" + var_name + "/hint_string", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); } + + // * Mapping + if (is_mapping_allowed()) { + p_list->push_back(PropertyInfo(Variant::NIL, "Mapping", PROPERTY_HINT_NONE, "_mapping_", PROPERTY_USAGE_GROUP)); + for (const Pair &p : var_list) { + p_list->push_back(PropertyInfo(Variant::STRING_NAME, "_mapping_" + p.first, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + } + } } bool BlackboardPlan::_property_can_revert(const StringName &p_name) const { @@ -131,6 +161,15 @@ void BlackboardPlan::set_base_plan(const Ref &p_base) { notify_property_list_changed(); } +void BlackboardPlan::set_mapping_allowed(bool p_mapping_allowed) { + mapping_allowed = p_mapping_allowed; + emit_changed(); +} + +bool BlackboardPlan::has_mapping(const StringName &p_name) const { + return is_mapping_allowed() && parent_scope_mapping.has(p_name) && parent_scope_mapping[p_name] != StringName(); +} + void BlackboardPlan::set_prefetch_nodepath_vars(bool p_enable) { prefetch_nodepath_vars = p_enable; emit_changed(); @@ -335,12 +374,11 @@ inline void bb_add_var_dup_with_prefetch(const Ref &p_blackboard, co } } -Ref BlackboardPlan::create_blackboard(Node *p_node) { +Ref BlackboardPlan::create_blackboard(Node *p_node, const Ref &p_parent_scope) { ERR_FAIL_COND_V(p_node == nullptr && prefetch_nodepath_vars, memnew(Blackboard)); Ref bb = memnew(Blackboard); - for (const Pair &p : var_list) { - bb_add_var_dup_with_prefetch(bb, p.first, p.second, prefetch_nodepath_vars, p_node); - } + bb->set_parent(p_parent_scope); + populate_blackboard(bb, false, p_node); return bb; } @@ -351,6 +389,13 @@ void BlackboardPlan::populate_blackboard(const Ref &p_blackboard, bo continue; } bb_add_var_dup_with_prefetch(p_blackboard, p.first, p.second, prefetch_nodepath_vars, p_node); + if (parent_scope_mapping.has(p.first)) { + StringName target_var = parent_scope_mapping[p.first]; + if (target_var != StringName()) { + ERR_CONTINUE_MSG(p_blackboard->get_parent() == nullptr, vformat("BlackboardPlan: Cannot link variable $%s to parent scope because the parent scope is not set.", p.first)); + p_blackboard->link_var(p.first, p_blackboard->get_parent(), target_var); + } + } } } diff --git a/blackboard/blackboard_plan.h b/blackboard/blackboard_plan.h index 83fdd45..6a7d665 100644 --- a/blackboard/blackboard_plan.h +++ b/blackboard/blackboard_plan.h @@ -36,6 +36,11 @@ private: // and only the values can be different in those variables. Ref base; + // Mapping between variables in this plan and their parent scope names. + // Used for linking variables to their parent scope counterparts upon Blackboard creation/population. + HashMap parent_scope_mapping; + bool mapping_allowed = true; + // If true, NodePath variables will be prefetched, so that the vars will contain node pointers instead (upon BB creation/population). bool prefetch_nodepath_vars = true; @@ -52,6 +57,10 @@ public: void set_base_plan(const Ref &p_base); Ref get_base_plan() const { return base; } + void set_mapping_allowed(bool p_mapping_allowed); + bool is_mapping_allowed() const { return mapping_allowed; } + bool has_mapping(const StringName &p_name) const; + void set_prefetch_nodepath_vars(bool p_enable); bool is_prefetching_nodepath_vars() const; @@ -72,7 +81,7 @@ public: void sync_with_base_plan(); _FORCE_INLINE_ bool is_derived() const { return base.is_valid(); } - Ref create_blackboard(Node *p_agent); + Ref create_blackboard(Node *p_agent, const Ref &p_parent_scope = Ref()); void populate_blackboard(const Ref &p_blackboard, bool overwrite, Node *p_node); BlackboardPlan(); From 2d493a76bd02eb8c569949c9b2ea2ae357e653d9 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Tue, 14 May 2024 09:29:56 +0200 Subject: [PATCH 02/20] BlackboardPlan: Improve mapping and serialize --- blackboard/blackboard_plan.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/blackboard/blackboard_plan.cpp b/blackboard/blackboard_plan.cpp index f9c97ec..2ce7dc5 100644 --- a/blackboard/blackboard_plan.cpp +++ b/blackboard/blackboard_plan.cpp @@ -24,8 +24,10 @@ bool BlackboardPlan::_set(const StringName &p_name, const Variant &p_value) { } return true; } - if (name_str.begins_with("_mapping_")) { - StringName mapped_var_name = name_str.trim_prefix("_mapping_"); + + // * Mapping + if (name_str.begins_with("mapping/")) { + StringName mapped_var_name = name_str.get_slicec('/', 1); ERR_FAIL_COND_V(!has_var(mapped_var_name), false); parent_scope_mapping[mapped_var_name] = p_value; return true; @@ -69,8 +71,11 @@ bool BlackboardPlan::_get(const StringName &p_name, Variant &r_ret) const { } return true; } - if (name_str.begins_with("_mapping_")) { - String mapped_var_name = name_str.trim_prefix("_mapping_"); + + // * Mapping + if (name_str.begins_with("mapping/")) { + StringName mapped_var_name = name_str.get_slicec('/', 1); + ERR_FAIL_COND_V(mapped_var_name == StringName(), false); if (parent_scope_mapping.has(mapped_var_name)) { r_ret = parent_scope_mapping[mapped_var_name]; } else { @@ -83,7 +88,6 @@ bool BlackboardPlan::_get(const StringName &p_name, Variant &r_ret) const { if (!name_str.begins_with("var/")) { return false; } - StringName var_name = name_str.get_slicec('/', 1); String what = name_str.get_slicec('/', 2); ERR_FAIL_COND_V(!var_map.has(var_name), false); @@ -131,9 +135,9 @@ void BlackboardPlan::_get_property_list(List *p_list) const { // * Mapping if (is_mapping_allowed()) { - p_list->push_back(PropertyInfo(Variant::NIL, "Mapping", PROPERTY_HINT_NONE, "_mapping_", PROPERTY_USAGE_GROUP)); + p_list->push_back(PropertyInfo(Variant::NIL, "Mapping", PROPERTY_HINT_NONE, "mapping/", PROPERTY_USAGE_GROUP)); for (const Pair &p : var_list) { - p_list->push_back(PropertyInfo(Variant::STRING_NAME, "_mapping_" + p.first, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + p_list->push_back(PropertyInfo(Variant::STRING_NAME, "mapping/" + p.first, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); } } } From 0d1e846d931fe36758db192eabd33c66054e2d2a Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Tue, 14 May 2024 11:39:32 +0200 Subject: [PATCH 03/20] BlackboardPlan: Use mapping with BTSubtree --- blackboard/blackboard_plan.cpp | 13 ++++++++----- blackboard/blackboard_plan.h | 9 ++++++--- bt/behavior_tree.cpp | 15 +++++++++++++++ bt/behavior_tree.h | 2 ++ bt/tasks/bt_task.cpp | 14 ++++++++++++++ bt/tasks/bt_task.h | 10 ++++++++++ bt/tasks/decorators/bt_subtree.cpp | 4 ++++ 7 files changed, 59 insertions(+), 8 deletions(-) diff --git a/blackboard/blackboard_plan.cpp b/blackboard/blackboard_plan.cpp index 2ce7dc5..0ea59f7 100644 --- a/blackboard/blackboard_plan.cpp +++ b/blackboard/blackboard_plan.cpp @@ -134,7 +134,7 @@ void BlackboardPlan::_get_property_list(List *p_list) const { } // * Mapping - if (is_mapping_allowed()) { + if (is_mapping_enabled()) { p_list->push_back(PropertyInfo(Variant::NIL, "Mapping", PROPERTY_HINT_NONE, "mapping/", PROPERTY_USAGE_GROUP)); for (const Pair &p : var_list) { p_list->push_back(PropertyInfo(Variant::STRING_NAME, "mapping/" + p.first, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); @@ -165,13 +165,13 @@ void BlackboardPlan::set_base_plan(const Ref &p_base) { notify_property_list_changed(); } -void BlackboardPlan::set_mapping_allowed(bool p_mapping_allowed) { - mapping_allowed = p_mapping_allowed; - emit_changed(); +void BlackboardPlan::set_parent_scope_plan(const Ref &p_plan) { + parent_scope_plan = p_plan; + notify_property_list_changed(); } bool BlackboardPlan::has_mapping(const StringName &p_name) const { - return is_mapping_allowed() && parent_scope_mapping.has(p_name) && parent_scope_mapping[p_name] != StringName(); + return is_mapping_enabled() && parent_scope_mapping.has(p_name) && parent_scope_mapping[p_name] != StringName(); } void BlackboardPlan::set_prefetch_nodepath_vars(bool p_enable) { @@ -409,6 +409,9 @@ void BlackboardPlan::_bind_methods() { ClassDB::bind_method(D_METHOD("set_base_plan", "blackboard_plan"), &BlackboardPlan::set_base_plan); ClassDB::bind_method(D_METHOD("get_base_plan"), &BlackboardPlan::get_base_plan); + ClassDB::bind_method(D_METHOD("set_parent_scope_plan", "blackboard_plan"), &BlackboardPlan::set_parent_scope_plan); + ClassDB::bind_method(D_METHOD("get_parent_scope_plan"), &BlackboardPlan::get_parent_scope_plan); + ClassDB::bind_method(D_METHOD("is_mapping_enabled"), &BlackboardPlan::is_mapping_enabled); ClassDB::bind_method(D_METHOD("is_derived"), &BlackboardPlan::is_derived); ClassDB::bind_method(D_METHOD("sync_with_base_plan"), &BlackboardPlan::sync_with_base_plan); ClassDB::bind_method(D_METHOD("create_blackboard", "node"), &BlackboardPlan::create_blackboard); diff --git a/blackboard/blackboard_plan.h b/blackboard/blackboard_plan.h index 6a7d665..d24edab 100644 --- a/blackboard/blackboard_plan.h +++ b/blackboard/blackboard_plan.h @@ -39,7 +39,9 @@ private: // Mapping between variables in this plan and their parent scope names. // Used for linking variables to their parent scope counterparts upon Blackboard creation/population. HashMap parent_scope_mapping; - bool mapping_allowed = true; + // BlackboardPlan that will be used in parent scope Blackboard creation at runtime. + // Used to provide hints in the inspector. When set, mapping is enabled in the inspector. + Ref parent_scope_plan; // If true, NodePath variables will be prefetched, so that the vars will contain node pointers instead (upon BB creation/population). bool prefetch_nodepath_vars = true; @@ -57,8 +59,9 @@ public: void set_base_plan(const Ref &p_base); Ref get_base_plan() const { return base; } - void set_mapping_allowed(bool p_mapping_allowed); - bool is_mapping_allowed() const { return mapping_allowed; } + void set_parent_scope_plan(const Ref &p_plan); + Ref get_parent_scope_plan() const { return parent_scope_plan; } + bool is_mapping_enabled() const { return parent_scope_plan.is_valid(); } bool has_mapping(const StringName &p_name) const; void set_prefetch_nodepath_vars(bool p_enable); diff --git a/bt/behavior_tree.cpp b/bt/behavior_tree.cpp index 817b8a6..45d403f 100644 --- a/bt/behavior_tree.cpp +++ b/bt/behavior_tree.cpp @@ -48,11 +48,14 @@ void BehaviorTree::set_blackboard_plan(const Ref &p_plan) { blackboard_plan->connect(LW_NAME(changed), callable_mp(this, &BehaviorTree::_plan_changed)); } + _set_editor_behavior_tree_hint(); _plan_changed(); } void BehaviorTree::set_root_task(const Ref &p_value) { + _unset_editor_behavior_tree_hint(); root_task = p_value; + _set_editor_behavior_tree_hint(); emit_changed(); } @@ -85,6 +88,18 @@ void BehaviorTree::_plan_changed() { emit_changed(); } +void BehaviorTree::_set_editor_behavior_tree_hint() { + if (root_task.is_valid()) { + root_task->data.behavior_tree = Ref(this); + } +} + +void BehaviorTree::_unset_editor_behavior_tree_hint() { + if (root_task.is_valid()) { + root_task->data.behavior_tree.unref(); + } +} + void BehaviorTree::_bind_methods() { ClassDB::bind_method(D_METHOD("set_description", "description"), &BehaviorTree::set_description); ClassDB::bind_method(D_METHOD("get_description"), &BehaviorTree::get_description); diff --git a/bt/behavior_tree.h b/bt/behavior_tree.h index 01ae806..4d71b9d 100644 --- a/bt/behavior_tree.h +++ b/bt/behavior_tree.h @@ -33,6 +33,8 @@ private: Ref root_task; void _plan_changed(); + void _set_editor_behavior_tree_hint(); + void _unset_editor_behavior_tree_hint(); protected: static void _bind_methods(); diff --git a/bt/tasks/bt_task.cpp b/bt/tasks/bt_task.cpp index 9a5e284..7bc317b 100644 --- a/bt/tasks/bt_task.cpp +++ b/bt/tasks/bt_task.cpp @@ -14,6 +14,7 @@ #include "../../blackboard/blackboard.h" #include "../../util/limbo_string_names.h" #include "../../util/limbo_utility.h" +#include "../behavior_tree.h" #include "bt_comment.h" #ifdef LIMBOAI_MODULE @@ -376,6 +377,18 @@ void BTTask::print_tree(int p_initial_tabs) { } } +Ref BTTask::editor_get_behavior_tree() { + BTTask *task = this; + while (task->data.behavior_tree.is_null() && task->get_parent().is_valid()) { + task = task->data.parent; + } + return task->data.behavior_tree; +} + +void BTTask::editor_set_behavior_tree(const Ref &p_bt) { + data.behavior_tree = p_bt; +} + void BTTask::_bind_methods() { // Public Methods. ClassDB::bind_method(D_METHOD("is_root"), &BTTask::is_root); @@ -397,6 +410,7 @@ void BTTask::_bind_methods() { ClassDB::bind_method(D_METHOD("print_tree", "initial_tabs"), &BTTask::print_tree, Variant(0)); ClassDB::bind_method(D_METHOD("get_task_name"), &BTTask::get_task_name); ClassDB::bind_method(D_METHOD("abort"), &BTTask::abort); + ClassDB::bind_method(D_METHOD("editor_get_behavior_tree"), &BTTask::editor_get_behavior_tree); // Properties, setters and getters. ClassDB::bind_method(D_METHOD("get_agent"), &BTTask::get_agent); diff --git a/bt/tasks/bt_task.h b/bt/tasks/bt_task.h index e9017ad..446e36d 100644 --- a/bt/tasks/bt_task.h +++ b/bt/tasks/bt_task.h @@ -42,6 +42,8 @@ using namespace godot; #endif // LIMBOAI_GDEXTENSION +class BehaviorTree; + /** * Base class for BTTask. * Note: In order to properly return Status in the _tick virtual method (GDVIRTUAL1R...) @@ -82,6 +84,9 @@ private: Status status = FRESH; double elapsed = 0.0; bool display_collapsed = false; +#ifdef TOOLS_ENABLED + Ref behavior_tree; +#endif } data; Array _get_children() const; @@ -162,6 +167,11 @@ public: void print_tree(int p_initial_tabs = 0); +#ifdef TOOLS_ENABLED + Ref editor_get_behavior_tree(); + void editor_set_behavior_tree(const Ref &p_bt); +#endif + BTTask(); ~BTTask(); }; diff --git a/bt/tasks/decorators/bt_subtree.cpp b/bt/tasks/decorators/bt_subtree.cpp index 9124912..331d538 100644 --- a/bt/tasks/decorators/bt_subtree.cpp +++ b/bt/tasks/decorators/bt_subtree.cpp @@ -30,6 +30,10 @@ void BTSubtree::_update_blackboard_plan() { set_blackboard_plan(Ref(memnew(BlackboardPlan))); } get_blackboard_plan()->set_base_plan(subtree.is_valid() ? subtree->get_blackboard_plan() : nullptr); + +#ifdef TOOLS_ENABLED + get_blackboard_plan()->set_parent_scope_plan(get_root()->editor_get_behavior_tree()->get_blackboard_plan()); +#endif // TOOLS_ENABLED } String BTSubtree::_generate_name() { From 549d73b8fcc8dd97fb17ee76b817fce65d08ba63 Mon Sep 17 00:00:00 2001 From: "Ola S." Date: Tue, 14 May 2024 13:25:24 +0200 Subject: [PATCH 04/20] Add icons for empty & error variable statuses --- icons/LimboVarEmpty.svg | 1 + icons/LimboVarError.svg | 1 + 2 files changed, 2 insertions(+) create mode 100644 icons/LimboVarEmpty.svg create mode 100644 icons/LimboVarError.svg diff --git a/icons/LimboVarEmpty.svg b/icons/LimboVarEmpty.svg new file mode 100644 index 0000000..24f5088 --- /dev/null +++ b/icons/LimboVarEmpty.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/icons/LimboVarError.svg b/icons/LimboVarError.svg new file mode 100644 index 0000000..563d762 --- /dev/null +++ b/icons/LimboVarError.svg @@ -0,0 +1 @@ + \ No newline at end of file From e43bc25d8249634705f16464105a178e1a2e035c Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Tue, 14 May 2024 13:29:04 +0200 Subject: [PATCH 05/20] BlackboardPlan: Provide editor hints for mappings --- editor/editor_property_variable_name.cpp | 51 ++++++++++++++++++++---- editor/editor_property_variable_name.h | 9 ++++- util/limbo_string_names.cpp | 2 + util/limbo_string_names.h | 2 + 4 files changed, 55 insertions(+), 9 deletions(-) diff --git a/editor/editor_property_variable_name.cpp b/editor/editor_property_variable_name.cpp index 4a8190f..9387fc5 100644 --- a/editor/editor_property_variable_name.cpp +++ b/editor/editor_property_variable_name.cpp @@ -71,9 +71,21 @@ void EditorPropertyVariableName::_update_status() { if (plan.is_null()) { return; } - if (plan->has_var(name_edit->get_text())) { - BUTTON_SET_ICON(status_btn, theme_cache.var_exists_icon); - status_btn->set_tooltip_text(TTR("This variable is present in the blackboard plan.\nClick to open the blackboard plan.")); + String var_name = name_edit->get_text(); + if (var_name.is_empty() && allow_empty) { + BUTTON_SET_ICON(status_btn, theme_cache.var_empty_icon); + status_btn->set_tooltip_text(TTR("Variable name not specified.\nClick to open the blackboard plan.")); + } else if (plan->has_var(var_name)) { + if (type_hint == Variant::NIL || plan->get_var(var_name).get_type() == type_hint) { + BUTTON_SET_ICON(status_btn, theme_cache.var_exists_icon); + status_btn->set_tooltip_text(TTR("This variable is present in the blackboard plan.\nClick to open the blackboard plan.")); + } else { + BUTTON_SET_ICON(status_btn, theme_cache.var_error_icon); + status_btn->set_tooltip_text(TTR(vformat( + "The %s variable in the blackboard plan is not of the same type as this variable (expected %s).\nClick to open the blackboard plan and fix the variable type.", + LimboUtility::get_singleton()->decorate_var(var_name), + Variant::get_type_name(type_hint)))); + } } else if (name_edit->get_text().begins_with("_")) { BUTTON_SET_ICON(status_btn, theme_cache.var_private_icon); status_btn->set_tooltip_text(TTR("This variable is private and is not included in the blackboard plan.\nClick to open the blackboard plan.")); @@ -119,8 +131,10 @@ void EditorPropertyVariableName::_update_property() { _update_status(); } -void EditorPropertyVariableName::setup(const Ref &p_plan) { +void EditorPropertyVariableName::setup(const Ref &p_plan, bool p_allow_empty, Variant::Type p_type_hint) { plan = p_plan; + allow_empty = p_allow_empty; + type_hint = p_type_hint; _update_status(); } @@ -148,6 +162,8 @@ void EditorPropertyVariableName::_notification(int p_what) { theme_cache.var_exists_icon = LimboUtility::get_singleton()->get_task_icon(LW_NAME(LimboVarExists)); theme_cache.var_not_found_icon = LimboUtility::get_singleton()->get_task_icon(LW_NAME(LimboVarNotFound)); theme_cache.var_private_icon = LimboUtility::get_singleton()->get_task_icon(LW_NAME(LimboVarPrivate)); + theme_cache.var_empty_icon = LimboUtility::get_singleton()->get_task_icon(LW_NAME(LimboVarEmpty)); + theme_cache.var_error_icon = LimboUtility::get_singleton()->get_task_icon(LW_NAME(LimboVarError)); } break; } } @@ -192,6 +208,10 @@ bool EditorInspectorPluginVariableName::_can_handle(Object *p_object) const { if (param.is_valid()) { return true; } + Ref plan = Object::cast_to(p_object); + if (plan.is_valid()) { + return true; + } return false; } @@ -200,13 +220,30 @@ bool EditorInspectorPluginVariableName::parse_property(Object *p_object, const V #elif LIMBOAI_GDEXTENSION bool EditorInspectorPluginVariableName::_parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField p_usage, const bool p_wide) { #endif - if (!(p_type == Variant::Type::STRING_NAME || p_type == Variant::Type::STRING) || !(p_path.ends_with("_var") || p_path.ends_with("variable"))) { + bool is_mapping = p_path.begins_with("mapping/"); + if (!(p_type == Variant::Type::STRING_NAME || p_type == Variant::Type::STRING) || !(is_mapping || p_path.ends_with("_var") || p_path.ends_with("variable"))) { return false; } + Ref plan; + Variant::Type type_hint = Variant::NIL; + if (is_mapping) { + plan.reference_ptr(Object::cast_to(p_object)); + ERR_FAIL_NULL_V(plan, false); + String var_name = p_path.trim_prefix("mapping/"); + if (plan->has_var(var_name)) { + BBVariable variable = plan->get_var(var_name); + type_hint = variable.get_type(); + } + plan = plan->get_parent_scope_plan(); + ERR_FAIL_NULL_V(plan, false); + } else { + plan = plan_getter.call(); + } + EditorPropertyVariableName *ed = memnew(EditorPropertyVariableName); - ed->setup(plan_getter.call()); - add_property_editor(p_path, ed); + ed->setup(plan, is_mapping, type_hint); + add_property_editor(p_path, ed, type_hint); return true; } diff --git a/editor/editor_property_variable_name.h b/editor/editor_property_variable_name.h index 19cbe31..5af68f1 100644 --- a/editor/editor_property_variable_name.h +++ b/editor/editor_property_variable_name.h @@ -33,15 +33,20 @@ class EditorPropertyVariableName : public EditorProperty { private: struct ThemeCache { + Ref var_add_icon; + Ref var_empty_icon; + Ref var_error_icon; Ref var_exists_icon; Ref var_not_found_icon; - Ref var_add_icon; Ref var_private_icon; }; ThemeCache theme_cache; Ref plan; + bool allow_empty = false; + Variant::Type type_hint = Variant::NIL; + LineEdit *name_edit; Button *drop_btn; Button *status_btn; @@ -68,7 +73,7 @@ public: virtual void _update_property() override; #endif - void setup(const Ref &p_plan); + void setup(const Ref &p_plan, bool p_allow_empty = false, Variant::Type p_type_hint = Variant::NIL); EditorPropertyVariableName(); }; diff --git a/util/limbo_string_names.cpp b/util/limbo_string_names.cpp index a223ded..46595f7 100644 --- a/util/limbo_string_names.cpp +++ b/util/limbo_string_names.cpp @@ -105,6 +105,8 @@ LimboStringNames::LimboStringNames() { LimboPercent = SN("LimboPercent"); LimboSelectAll = SN("LimboSelectAll"); LimboVarAdd = SN("LimboVarAdd"); + LimboVarEmpty = SN("LimboVarEmpty"); + LimboVarError = SN("LimboVarError"); LimboVarExists = SN("LimboVarExists"); LimboVarNotFound = SN("LimboVarNotFound"); LimboVarPrivate = SN("LimboVarPrivate"); diff --git a/util/limbo_string_names.h b/util/limbo_string_names.h index 10e6542..8311e06 100644 --- a/util/limbo_string_names.h +++ b/util/limbo_string_names.h @@ -122,6 +122,8 @@ public: StringName LimboPercent; StringName LimboSelectAll; StringName LimboVarAdd; + StringName LimboVarEmpty; + StringName LimboVarError; StringName LimboVarExists; StringName LimboVarNotFound; StringName LimboVarPrivate; From a1cdff2e2ed7ae39cbcea19cf90923042864b6b9 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Tue, 14 May 2024 19:47:05 +0200 Subject: [PATCH 06/20] Fix issues with mapping in BTSubtree --- blackboard/blackboard_plan.cpp | 3 +-- bt/behavior_tree.cpp | 1 - bt/tasks/decorators/bt_new_scope.cpp | 23 +++++++++++++++++++---- bt/tasks/decorators/bt_new_scope.h | 2 ++ bt/tasks/decorators/bt_subtree.cpp | 4 ---- 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/blackboard/blackboard_plan.cpp b/blackboard/blackboard_plan.cpp index 0ea59f7..c05cfd6 100644 --- a/blackboard/blackboard_plan.cpp +++ b/blackboard/blackboard_plan.cpp @@ -28,7 +28,6 @@ bool BlackboardPlan::_set(const StringName &p_name, const Variant &p_value) { // * Mapping if (name_str.begins_with("mapping/")) { StringName mapped_var_name = name_str.get_slicec('/', 1); - ERR_FAIL_COND_V(!has_var(mapped_var_name), false); parent_scope_mapping[mapped_var_name] = p_value; return true; } @@ -382,7 +381,7 @@ Ref BlackboardPlan::create_blackboard(Node *p_node, const Ref bb = memnew(Blackboard); bb->set_parent(p_parent_scope); - populate_blackboard(bb, false, p_node); + populate_blackboard(bb, true, p_node); return bb; } diff --git a/bt/behavior_tree.cpp b/bt/behavior_tree.cpp index 45d403f..3482462 100644 --- a/bt/behavior_tree.cpp +++ b/bt/behavior_tree.cpp @@ -48,7 +48,6 @@ void BehaviorTree::set_blackboard_plan(const Ref &p_plan) { blackboard_plan->connect(LW_NAME(changed), callable_mp(this, &BehaviorTree::_plan_changed)); } - _set_editor_behavior_tree_hint(); _plan_changed(); } diff --git a/bt/tasks/decorators/bt_new_scope.cpp b/bt/tasks/decorators/bt_new_scope.cpp index 5aaa4bc..48a3319 100644 --- a/bt/tasks/decorators/bt_new_scope.cpp +++ b/bt/tasks/decorators/bt_new_scope.cpp @@ -11,28 +11,43 @@ #include "bt_new_scope.h" +#include "../../behavior_tree.h" + void BTNewScope::set_blackboard_plan(const Ref &p_plan) { blackboard_plan = p_plan; if (blackboard_plan.is_null()) { blackboard_plan.instantiate(); } + _update_blackboard_plan(); + +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + callable_mp(this, &BTNewScope::_set_parent_scope_plan_from_bt).call_deferred(); + } +#endif // TOOLS_ENABLED + emit_changed(); } +void BTNewScope::_set_parent_scope_plan_from_bt() { + ERR_FAIL_NULL(get_blackboard_plan()); + Ref bt = get_root()->editor_get_behavior_tree(); + ERR_FAIL_NULL(bt); + get_blackboard_plan()->set_parent_scope_plan(bt->get_blackboard_plan()); +} + 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); Ref bb; if (blackboard_plan.is_valid()) { - bb = blackboard_plan->create_blackboard(p_agent); + bb = blackboard_plan->create_blackboard(p_agent, p_blackboard); } else { bb = Ref(memnew(Blackboard)); + bb->set_parent(p_blackboard); } - - bb->set_parent(p_blackboard); - BTDecorator::initialize(p_agent, bb, p_scene_root); } diff --git a/bt/tasks/decorators/bt_new_scope.h b/bt/tasks/decorators/bt_new_scope.h index a7e0020..df2c505 100644 --- a/bt/tasks/decorators/bt_new_scope.h +++ b/bt/tasks/decorators/bt_new_scope.h @@ -23,6 +23,8 @@ class BTNewScope : public BTDecorator { private: Ref blackboard_plan; + void _set_parent_scope_plan_from_bt(); + protected: static void _bind_methods(); diff --git a/bt/tasks/decorators/bt_subtree.cpp b/bt/tasks/decorators/bt_subtree.cpp index 331d538..9124912 100644 --- a/bt/tasks/decorators/bt_subtree.cpp +++ b/bt/tasks/decorators/bt_subtree.cpp @@ -30,10 +30,6 @@ void BTSubtree::_update_blackboard_plan() { set_blackboard_plan(Ref(memnew(BlackboardPlan))); } get_blackboard_plan()->set_base_plan(subtree.is_valid() ? subtree->get_blackboard_plan() : nullptr); - -#ifdef TOOLS_ENABLED - get_blackboard_plan()->set_parent_scope_plan(get_root()->editor_get_behavior_tree()->get_blackboard_plan()); -#endif // TOOLS_ENABLED } String BTSubtree::_generate_name() { From 3b12288ae04237daa19c4709c44771e7eff8fae1 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Tue, 14 May 2024 20:25:18 +0200 Subject: [PATCH 07/20] BlackboardPlan: Serialize only non-empty mapping values --- blackboard/blackboard_plan.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/blackboard/blackboard_plan.cpp b/blackboard/blackboard_plan.cpp index c05cfd6..47e9971 100644 --- a/blackboard/blackboard_plan.cpp +++ b/blackboard/blackboard_plan.cpp @@ -28,7 +28,12 @@ bool BlackboardPlan::_set(const StringName &p_name, const Variant &p_value) { // * Mapping if (name_str.begins_with("mapping/")) { StringName mapped_var_name = name_str.get_slicec('/', 1); - parent_scope_mapping[mapped_var_name] = p_value; + StringName value = p_value; + if (value == StringName()) { + parent_scope_mapping.erase(mapped_var_name); + } else { + parent_scope_mapping[mapped_var_name] = value; + } return true; } @@ -136,16 +141,25 @@ void BlackboardPlan::_get_property_list(List *p_list) const { if (is_mapping_enabled()) { p_list->push_back(PropertyInfo(Variant::NIL, "Mapping", PROPERTY_HINT_NONE, "mapping/", PROPERTY_USAGE_GROUP)); for (const Pair &p : var_list) { - p_list->push_back(PropertyInfo(Variant::STRING_NAME, "mapping/" + p.first, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + // Serialize only non-empty mappings. + PropertyUsageFlags usage = has_mapping(p.first) ? PROPERTY_USAGE_DEFAULT : PROPERTY_USAGE_EDITOR; + p_list->push_back(PropertyInfo(Variant::STRING_NAME, "mapping/" + p.first, PROPERTY_HINT_NONE, "", usage)); } } } bool BlackboardPlan::_property_can_revert(const StringName &p_name) const { + if (String(p_name).begins_with("mapping/")) { + return true; + } return base.is_valid() && base->var_map.has(p_name); } bool BlackboardPlan::_property_get_revert(const StringName &p_name, Variant &r_property) const { + if (String(p_name).begins_with("mapping/")) { + r_property = StringName(); + return true; + } if (base->var_map.has(p_name)) { r_property = base->var_map[p_name].get_value(); return true; From ef1c1e5192976a32619eb89577e89896e80498a7 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Tue, 14 May 2024 22:03:29 +0200 Subject: [PATCH 08/20] Fix circular ref & non-tools compilation errors --- bt/behavior_tree.cpp | 12 ++++++++++-- bt/behavior_tree.h | 3 +++ bt/tasks/bt_task.cpp | 12 +++++++++--- bt/tasks/bt_task.h | 2 +- bt/tasks/decorators/bt_new_scope.cpp | 2 ++ bt/tasks/decorators/bt_new_scope.h | 2 ++ 6 files changed, 27 insertions(+), 6 deletions(-) diff --git a/bt/behavior_tree.cpp b/bt/behavior_tree.cpp index 3482462..b15f480 100644 --- a/bt/behavior_tree.cpp +++ b/bt/behavior_tree.cpp @@ -52,9 +52,13 @@ void BehaviorTree::set_blackboard_plan(const Ref &p_plan) { } void BehaviorTree::set_root_task(const Ref &p_value) { +#ifdef TOOLS_ENABLED _unset_editor_behavior_tree_hint(); +#endif // TOOLS_ENABLED root_task = p_value; +#ifdef TOOLS_ENABLED _set_editor_behavior_tree_hint(); +#endif // TOOLS_ENABLED emit_changed(); } @@ -87,18 +91,22 @@ void BehaviorTree::_plan_changed() { emit_changed(); } +#ifdef TOOLS_ENABLED + void BehaviorTree::_set_editor_behavior_tree_hint() { if (root_task.is_valid()) { - root_task->data.behavior_tree = Ref(this); + root_task->data.behavior_tree_id = this->get_instance_id(); } } void BehaviorTree::_unset_editor_behavior_tree_hint() { if (root_task.is_valid()) { - root_task->data.behavior_tree.unref(); + root_task->data.behavior_tree_id = ObjectID(); } } +#endif // TOOLS_ENABLED + void BehaviorTree::_bind_methods() { ClassDB::bind_method(D_METHOD("set_description", "description"), &BehaviorTree::set_description); ClassDB::bind_method(D_METHOD("get_description"), &BehaviorTree::get_description); diff --git a/bt/behavior_tree.h b/bt/behavior_tree.h index 4d71b9d..46507c5 100644 --- a/bt/behavior_tree.h +++ b/bt/behavior_tree.h @@ -33,8 +33,11 @@ private: Ref root_task; void _plan_changed(); + +#ifdef TOOLS_ENABLED void _set_editor_behavior_tree_hint(); void _unset_editor_behavior_tree_hint(); +#endif // TOOLS_ENABLED protected: static void _bind_methods(); diff --git a/bt/tasks/bt_task.cpp b/bt/tasks/bt_task.cpp index 7bc317b..4fa7ef1 100644 --- a/bt/tasks/bt_task.cpp +++ b/bt/tasks/bt_task.cpp @@ -377,18 +377,22 @@ void BTTask::print_tree(int p_initial_tabs) { } } +#ifdef TOOLS_ENABLED + Ref BTTask::editor_get_behavior_tree() { BTTask *task = this; - while (task->data.behavior_tree.is_null() && task->get_parent().is_valid()) { + while (task->data.behavior_tree_id.is_null() && task->get_parent().is_valid()) { task = task->data.parent; } - return task->data.behavior_tree; + return Object::cast_to(ObjectDB::get_instance(task->data.behavior_tree_id)); } void BTTask::editor_set_behavior_tree(const Ref &p_bt) { - data.behavior_tree = p_bt; + data.behavior_tree_id = p_bt->get_instance_id(); } +#endif // TOOLS_ENABLED + void BTTask::_bind_methods() { // Public Methods. ClassDB::bind_method(D_METHOD("is_root"), &BTTask::is_root); @@ -410,7 +414,9 @@ void BTTask::_bind_methods() { ClassDB::bind_method(D_METHOD("print_tree", "initial_tabs"), &BTTask::print_tree, Variant(0)); ClassDB::bind_method(D_METHOD("get_task_name"), &BTTask::get_task_name); ClassDB::bind_method(D_METHOD("abort"), &BTTask::abort); +#ifdef TOOLS_ENABLED ClassDB::bind_method(D_METHOD("editor_get_behavior_tree"), &BTTask::editor_get_behavior_tree); +#endif // TOOLS_ENABLED // Properties, setters and getters. ClassDB::bind_method(D_METHOD("get_agent"), &BTTask::get_agent); diff --git a/bt/tasks/bt_task.h b/bt/tasks/bt_task.h index 446e36d..b571c27 100644 --- a/bt/tasks/bt_task.h +++ b/bt/tasks/bt_task.h @@ -85,7 +85,7 @@ private: double elapsed = 0.0; bool display_collapsed = false; #ifdef TOOLS_ENABLED - Ref behavior_tree; + ObjectID behavior_tree_id; #endif } data; diff --git a/bt/tasks/decorators/bt_new_scope.cpp b/bt/tasks/decorators/bt_new_scope.cpp index 48a3319..c9a85b5 100644 --- a/bt/tasks/decorators/bt_new_scope.cpp +++ b/bt/tasks/decorators/bt_new_scope.cpp @@ -30,12 +30,14 @@ void BTNewScope::set_blackboard_plan(const Ref &p_plan) { emit_changed(); } +#ifdef TOOLS_ENABLED void BTNewScope::_set_parent_scope_plan_from_bt() { ERR_FAIL_NULL(get_blackboard_plan()); Ref bt = get_root()->editor_get_behavior_tree(); ERR_FAIL_NULL(bt); get_blackboard_plan()->set_parent_scope_plan(bt->get_blackboard_plan()); } +#endif // TOOLS_ENABLED void BTNewScope::initialize(Node *p_agent, const Ref &p_blackboard, Node *p_scene_root) { ERR_FAIL_COND(p_agent == nullptr); diff --git a/bt/tasks/decorators/bt_new_scope.h b/bt/tasks/decorators/bt_new_scope.h index df2c505..b3662f5 100644 --- a/bt/tasks/decorators/bt_new_scope.h +++ b/bt/tasks/decorators/bt_new_scope.h @@ -23,7 +23,9 @@ class BTNewScope : public BTDecorator { private: Ref blackboard_plan; +#ifdef TOOLS_ENABLED void _set_parent_scope_plan_from_bt(); +#endif // TOOLS_ENABLED protected: static void _bind_methods(); From c30c5a4d7a93d44a4a0bf6e8cbaa2a3197e7c578 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Tue, 14 May 2024 22:55:25 +0200 Subject: [PATCH 09/20] BlackboardPlan: Auto-fill type info when adding a missing variable for a mapping --- editor/blackboard_plan_editor.cpp | 23 ++++++++++++++++------- editor/blackboard_plan_editor.h | 6 +++++- editor/editor_property_bb_param.cpp | 2 +- editor/editor_property_variable_name.cpp | 24 +++++++++++++++--------- editor/editor_property_variable_name.h | 6 ++++-- 5 files changed, 41 insertions(+), 20 deletions(-) diff --git a/editor/blackboard_plan_editor.cpp b/editor/blackboard_plan_editor.cpp index a6f1223..c0424b8 100644 --- a/editor/blackboard_plan_editor.cpp +++ b/editor/blackboard_plan_editor.cpp @@ -54,8 +54,9 @@ void BlackboardPlanEditor::_add_var() { var_name = String(default_var_name) + itos(suffix); } - BBVariable var(Variant::Type::FLOAT); + BBVariable var(default_type, default_hint, default_hint_string); plan->add_var(var_name, var); + reset_defaults(); _refresh(); } @@ -127,10 +128,18 @@ void BlackboardPlanEditor::edit_plan(const Ref &p_plan) { _refresh(); } -void BlackboardPlanEditor::set_next_var_name(const StringName &p_name) { - if (String(p_name).is_valid_identifier()) { - default_var_name = p_name; - } +void BlackboardPlanEditor::set_defaults(const StringName &p_var_name, Variant::Type p_type, PropertyHint p_hint, String p_hint_string) { + default_var_name = p_var_name; + default_type = p_type; + default_hint = p_hint; + default_hint_string = p_hint_string; +} + +void BlackboardPlanEditor::reset_defaults() { + default_var_name = "var"; + default_type = Variant::FLOAT; + default_hint = PROPERTY_HINT_NONE; + default_hint_string = ""; } void BlackboardPlanEditor::_show_button_popup(Button *p_button, PopupMenu *p_popup, int p_index) { @@ -233,7 +242,7 @@ void BlackboardPlanEditor::_drag_button_gui_input(const Ref &p_event void BlackboardPlanEditor::_visibility_changed() { if (!is_visible() && plan.is_valid()) { plan->notify_property_list_changed(); - default_var_name = "var"; + reset_defaults(); } } @@ -367,7 +376,7 @@ void BlackboardPlanEditor::_notification(int p_what) { } BlackboardPlanEditor::BlackboardPlanEditor() { - default_var_name = "var"; + reset_defaults(); set_title(TTR("Manage Blackboard Plan")); diff --git a/editor/blackboard_plan_editor.h b/editor/blackboard_plan_editor.h index 7dcff2f..b1609a4 100644 --- a/editor/blackboard_plan_editor.h +++ b/editor/blackboard_plan_editor.h @@ -59,6 +59,9 @@ private: Ref plan; StringName default_var_name; + Variant::Type default_type = Variant::NIL; + PropertyHint default_hint = PROPERTY_HINT_NONE; + String default_hint_string; VBoxContainer *rows_vbox; Button *add_var_tool; @@ -99,7 +102,8 @@ public: _FORCE_INLINE_ static BlackboardPlanEditor *get_singleton() { return singleton; } void edit_plan(const Ref &p_plan); - void set_next_var_name(const StringName &p_name); + void set_defaults(const StringName &p_name, Variant::Type p_type = Variant::FLOAT, PropertyHint p_hint = PROPERTY_HINT_NONE, String p_hint_string = ""); + void reset_defaults(); BlackboardPlanEditor(); }; diff --git a/editor/editor_property_bb_param.cpp b/editor/editor_property_bb_param.cpp index 687b9eb..707fdbb 100644 --- a/editor/editor_property_bb_param.cpp +++ b/editor/editor_property_bb_param.cpp @@ -300,7 +300,7 @@ void EditorPropertyBBParam::update_property() { void EditorPropertyBBParam::setup(PropertyHint p_hint, const String &p_hint_text, const Ref &p_plan) { param_type = p_hint_text; property_hint = p_hint; - variable_editor->setup(p_plan); + variable_editor->setup(p_plan, false); variable_editor->set_name_split_ratio(0.0); } diff --git a/editor/editor_property_variable_name.cpp b/editor/editor_property_variable_name.cpp index 9387fc5..3e23977 100644 --- a/editor/editor_property_variable_name.cpp +++ b/editor/editor_property_variable_name.cpp @@ -76,7 +76,7 @@ void EditorPropertyVariableName::_update_status() { BUTTON_SET_ICON(status_btn, theme_cache.var_empty_icon); status_btn->set_tooltip_text(TTR("Variable name not specified.\nClick to open the blackboard plan.")); } else if (plan->has_var(var_name)) { - if (type_hint == Variant::NIL || plan->get_var(var_name).get_type() == type_hint) { + if (expected_type == Variant::NIL || plan->get_var(var_name).get_type() == expected_type) { BUTTON_SET_ICON(status_btn, theme_cache.var_exists_icon); status_btn->set_tooltip_text(TTR("This variable is present in the blackboard plan.\nClick to open the blackboard plan.")); } else { @@ -84,7 +84,7 @@ void EditorPropertyVariableName::_update_status() { status_btn->set_tooltip_text(TTR(vformat( "The %s variable in the blackboard plan is not of the same type as this variable (expected %s).\nClick to open the blackboard plan and fix the variable type.", LimboUtility::get_singleton()->decorate_var(var_name), - Variant::get_type_name(type_hint)))); + Variant::get_type_name(expected_type)))); } } else if (name_edit->get_text().begins_with("_")) { BUTTON_SET_ICON(status_btn, theme_cache.var_private_icon); @@ -98,7 +98,7 @@ void EditorPropertyVariableName::_update_status() { void EditorPropertyVariableName::_status_pressed() { ERR_FAIL_NULL(plan); if (!plan->has_var(name_edit->get_text())) { - BlackboardPlanEditor::get_singleton()->set_next_var_name(name_edit->get_text()); + BlackboardPlanEditor::get_singleton()->set_defaults(name_edit->get_text(), expected_type, expected_hint, expected_hint_string); } BlackboardPlanEditor::get_singleton()->edit_plan(plan); BlackboardPlanEditor::get_singleton()->popup_centered(); @@ -131,10 +131,12 @@ void EditorPropertyVariableName::_update_property() { _update_status(); } -void EditorPropertyVariableName::setup(const Ref &p_plan, bool p_allow_empty, Variant::Type p_type_hint) { +void EditorPropertyVariableName::setup(const Ref &p_plan, bool p_allow_empty, Variant::Type p_type, PropertyHint p_hint, String p_hint_string) { plan = p_plan; allow_empty = p_allow_empty; - type_hint = p_type_hint; + expected_type = p_type; + expected_hint = p_hint; + expected_hint_string = p_hint_string; _update_status(); } @@ -226,14 +228,18 @@ bool EditorInspectorPluginVariableName::_parse_property(Object *p_object, const } Ref plan; - Variant::Type type_hint = Variant::NIL; + Variant::Type expected_type = Variant::NIL; + PropertyHint expected_hint = PROPERTY_HINT_NONE; + String expected_hint_string; if (is_mapping) { plan.reference_ptr(Object::cast_to(p_object)); ERR_FAIL_NULL_V(plan, false); String var_name = p_path.trim_prefix("mapping/"); if (plan->has_var(var_name)) { BBVariable variable = plan->get_var(var_name); - type_hint = variable.get_type(); + expected_type = variable.get_type(); + expected_hint = variable.get_hint(); + expected_hint_string = variable.get_hint_string(); } plan = plan->get_parent_scope_plan(); ERR_FAIL_NULL_V(plan, false); @@ -242,8 +248,8 @@ bool EditorInspectorPluginVariableName::_parse_property(Object *p_object, const } EditorPropertyVariableName *ed = memnew(EditorPropertyVariableName); - ed->setup(plan, is_mapping, type_hint); - add_property_editor(p_path, ed, type_hint); + ed->setup(plan, is_mapping, expected_type, expected_hint, expected_hint_string); + add_property_editor(p_path, ed, expected_type); return true; } diff --git a/editor/editor_property_variable_name.h b/editor/editor_property_variable_name.h index 5af68f1..da75eab 100644 --- a/editor/editor_property_variable_name.h +++ b/editor/editor_property_variable_name.h @@ -45,7 +45,9 @@ private: Ref plan; bool allow_empty = false; - Variant::Type type_hint = Variant::NIL; + Variant::Type expected_type = Variant::NIL; + PropertyHint expected_hint = PROPERTY_HINT_NONE; + String expected_hint_string; LineEdit *name_edit; Button *drop_btn; @@ -73,7 +75,7 @@ public: virtual void _update_property() override; #endif - void setup(const Ref &p_plan, bool p_allow_empty = false, Variant::Type p_type_hint = Variant::NIL); + void setup(const Ref &p_plan, bool p_allow_empty, Variant::Type p_type = Variant::FLOAT, PropertyHint p_hint = PROPERTY_HINT_NONE, String p_hint_string = ""); EditorPropertyVariableName(); }; From a572613001b75daaef2cdab490aaf63bd63a0c1f Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Wed, 15 May 2024 11:38:53 +0200 Subject: [PATCH 10/20] BlackboardPlan: Utilize mapping in LimboHSM Also changes how parent plan providing is implemented (used for editor hints). --- blackboard/blackboard_plan.cpp | 8 ++++---- blackboard/blackboard_plan.h | 13 +++++++------ bt/tasks/decorators/bt_new_scope.cpp | 2 +- editor/editor_property_variable_name.cpp | 7 ++++++- hsm/limbo_state.cpp | 19 +++++++++++++++++++ hsm/limbo_state.h | 2 ++ 6 files changed, 39 insertions(+), 12 deletions(-) diff --git a/blackboard/blackboard_plan.cpp b/blackboard/blackboard_plan.cpp index 47e9971..2756c8b 100644 --- a/blackboard/blackboard_plan.cpp +++ b/blackboard/blackboard_plan.cpp @@ -178,8 +178,8 @@ void BlackboardPlan::set_base_plan(const Ref &p_base) { notify_property_list_changed(); } -void BlackboardPlan::set_parent_scope_plan(const Ref &p_plan) { - parent_scope_plan = p_plan; +void BlackboardPlan::set_parent_scope_plan_provider(const Callable &p_parent_scope_plan_provider) { + parent_scope_plan_provider = p_parent_scope_plan_provider; notify_property_list_changed(); } @@ -422,8 +422,8 @@ void BlackboardPlan::_bind_methods() { ClassDB::bind_method(D_METHOD("set_base_plan", "blackboard_plan"), &BlackboardPlan::set_base_plan); ClassDB::bind_method(D_METHOD("get_base_plan"), &BlackboardPlan::get_base_plan); - ClassDB::bind_method(D_METHOD("set_parent_scope_plan", "blackboard_plan"), &BlackboardPlan::set_parent_scope_plan); - ClassDB::bind_method(D_METHOD("get_parent_scope_plan"), &BlackboardPlan::get_parent_scope_plan); + ClassDB::bind_method(D_METHOD("set_parent_scope_plan_provider", "callable"), &BlackboardPlan::set_parent_scope_plan_provider); + ClassDB::bind_method(D_METHOD("get_parent_scope_plan_provider"), &BlackboardPlan::get_parent_scope_plan_provider); ClassDB::bind_method(D_METHOD("is_mapping_enabled"), &BlackboardPlan::is_mapping_enabled); ClassDB::bind_method(D_METHOD("is_derived"), &BlackboardPlan::is_derived); ClassDB::bind_method(D_METHOD("sync_with_base_plan"), &BlackboardPlan::sync_with_base_plan); diff --git a/blackboard/blackboard_plan.h b/blackboard/blackboard_plan.h index d24edab..21ccbbf 100644 --- a/blackboard/blackboard_plan.h +++ b/blackboard/blackboard_plan.h @@ -39,9 +39,9 @@ private: // Mapping between variables in this plan and their parent scope names. // Used for linking variables to their parent scope counterparts upon Blackboard creation/population. HashMap parent_scope_mapping; - // BlackboardPlan that will be used in parent scope Blackboard creation at runtime. - // Used to provide hints in the inspector. When set, mapping is enabled in the inspector. - Ref parent_scope_plan; + // Fetcher function for the parent scope plan. Funtion should return a Ref. + // Used in the inspector. When set, mapping feature becomes available. + Callable parent_scope_plan_provider; // If true, NodePath variables will be prefetched, so that the vars will contain node pointers instead (upon BB creation/population). bool prefetch_nodepath_vars = true; @@ -59,9 +59,10 @@ public: void set_base_plan(const Ref &p_base); Ref get_base_plan() const { return base; } - void set_parent_scope_plan(const Ref &p_plan); - Ref get_parent_scope_plan() const { return parent_scope_plan; } - bool is_mapping_enabled() const { return parent_scope_plan.is_valid(); } + void set_parent_scope_plan_provider(const Callable &p_parent_scope_plan_provider); + Callable get_parent_scope_plan_provider() const { return parent_scope_plan_provider; } + + bool is_mapping_enabled() const { return parent_scope_plan_provider.is_valid(); } bool has_mapping(const StringName &p_name) const; void set_prefetch_nodepath_vars(bool p_enable); diff --git a/bt/tasks/decorators/bt_new_scope.cpp b/bt/tasks/decorators/bt_new_scope.cpp index c9a85b5..5a2b1c4 100644 --- a/bt/tasks/decorators/bt_new_scope.cpp +++ b/bt/tasks/decorators/bt_new_scope.cpp @@ -35,7 +35,7 @@ void BTNewScope::_set_parent_scope_plan_from_bt() { ERR_FAIL_NULL(get_blackboard_plan()); Ref bt = get_root()->editor_get_behavior_tree(); ERR_FAIL_NULL(bt); - get_blackboard_plan()->set_parent_scope_plan(bt->get_blackboard_plan()); + get_blackboard_plan()->set_parent_scope_plan_provider(callable_mp(bt.ptr(), &BehaviorTree::get_blackboard_plan)); } #endif // TOOLS_ENABLED diff --git a/editor/editor_property_variable_name.cpp b/editor/editor_property_variable_name.cpp index 3e23977..939c5d9 100644 --- a/editor/editor_property_variable_name.cpp +++ b/editor/editor_property_variable_name.cpp @@ -241,7 +241,12 @@ bool EditorInspectorPluginVariableName::_parse_property(Object *p_object, const expected_hint = variable.get_hint(); expected_hint_string = variable.get_hint_string(); } - plan = plan->get_parent_scope_plan(); + if (plan->get_parent_scope_plan_provider().is_valid()) { + Ref parent_plan = plan->get_parent_scope_plan_provider().call(); + if (parent_plan.is_valid()) { + plan = parent_plan; + } + } ERR_FAIL_NULL_V(plan, false); } else { plan = plan_getter.call(); diff --git a/hsm/limbo_state.cpp b/hsm/limbo_state.cpp index 77554bb..f704dc1 100644 --- a/hsm/limbo_state.cpp +++ b/hsm/limbo_state.cpp @@ -22,12 +22,31 @@ void LimboState::set_blackboard_plan(const Ref &p_plan) { blackboard_plan = p_plan; + + if (Engine::get_singleton()->is_editor_hint() && blackboard_plan.is_valid()) { + blackboard_plan->set_parent_scope_plan_provider(callable_mp(this, &LimboState::_get_parent_scope_plan)); + } + _update_blackboard_plan(); } void LimboState::_update_blackboard_plan() { } +Ref LimboState::_get_parent_scope_plan() const { + BlackboardPlan *parent_plan = nullptr; + const LimboState *state = this; + while (state->get_parent() && IS_CLASS(state->get_parent(), LimboState)) { + state = Object::cast_to(state->get_parent()); + ERR_FAIL_NULL_V(state, parent_plan); + if (state->blackboard_plan.is_valid()) { + parent_plan = state->blackboard_plan.ptr(); + break; + } + } + return parent_plan; +} + LimboState *LimboState::get_root() const { const Node *state = this; while (state->get_parent() && IS_CLASS(state->get_parent(), LimboState)) { diff --git a/hsm/limbo_state.h b/hsm/limbo_state.h index 69bc2cf..a4d9b00 100644 --- a/hsm/limbo_state.h +++ b/hsm/limbo_state.h @@ -38,6 +38,8 @@ private: HashMap handlers; Callable guard_callable; + Ref _get_parent_scope_plan() const; + protected: friend LimboHSM; From d36f8f1122a3dd3c0b9f980c2ca638c9c7046cfc Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Wed, 15 May 2024 11:43:31 +0200 Subject: [PATCH 11/20] Fix variables missing from BTState blackboard Non-overridden variables could be missing at runtime in the BTState blackboard due to a bug this commit fixes. --- bt/bt_state.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bt/bt_state.cpp b/bt/bt_state.cpp index 1a29f03..dd1c659 100644 --- a/bt/bt_state.cpp +++ b/bt/bt_state.cpp @@ -32,10 +32,10 @@ void BTState::set_behavior_tree(const Ref &p_tree) { p_tree->connect(LW_NAME(plan_changed), callable_mp(this, &BTState::_update_blackboard_plan)); } behavior_tree = p_tree; - _update_blackboard_plan(); } else { behavior_tree = p_tree; } + _update_blackboard_plan(); } void BTState::_update_blackboard_plan() { From c6b1a4062703ddcf63ae6f4a3699abc9f61e6679 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Wed, 15 May 2024 12:50:33 +0200 Subject: [PATCH 12/20] BlackboardPlan: Update inspector upon mapping editing finished --- blackboard/blackboard_plan.cpp | 5 ++++- editor/editor_property_variable_name.cpp | 17 +++++++++++++---- editor/editor_property_variable_name.h | 3 ++- util/limbo_string_names.cpp | 1 + util/limbo_string_names.h | 1 + 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/blackboard/blackboard_plan.cpp b/blackboard/blackboard_plan.cpp index 2756c8b..1720e72 100644 --- a/blackboard/blackboard_plan.cpp +++ b/blackboard/blackboard_plan.cpp @@ -11,6 +11,8 @@ #include "blackboard_plan.h" +#include "../util/limbo_utility.h" + bool BlackboardPlan::_set(const StringName &p_name, const Variant &p_value) { String name_str = p_name; @@ -34,6 +36,7 @@ bool BlackboardPlan::_set(const StringName &p_name, const Variant &p_value) { } else { parent_scope_mapping[mapped_var_name] = value; } + notify_property_list_changed(); return true; } @@ -69,7 +72,7 @@ bool BlackboardPlan::_get(const StringName &p_name, Variant &r_ret) const { // * Editor if (var_map.has(p_name)) { if (has_mapping(p_name)) { - r_ret = "Mapped to $" + parent_scope_mapping[p_name]; + r_ret = "Mapped to " + LimboUtility::get_singleton()->decorate_var(parent_scope_mapping[p_name]); } else { r_ret = var_map[p_name].get_value(); } diff --git a/editor/editor_property_variable_name.cpp b/editor/editor_property_variable_name.cpp index 939c5d9..176c236 100644 --- a/editor/editor_property_variable_name.cpp +++ b/editor/editor_property_variable_name.cpp @@ -54,15 +54,22 @@ void EditorPropertyVariableName::_show_variables_popup() { variables_popup->popup(rect); } -void EditorPropertyVariableName::_name_changed(const String &p_new_name) { - emit_changed(get_edited_property(), p_new_name); +void EditorPropertyVariableName::_name_changed(const String &p_new_name, bool p_changing) { + emit_changed(get_edited_property(), p_new_name, StringName(), p_changing); _update_status(); } +void EditorPropertyVariableName::_name_submitted() { + _name_changed(name_edit->get_text(), false); + if (name_edit->has_focus()) { + name_edit->release_focus(); + } +} + void EditorPropertyVariableName::_variable_selected(int p_id) { String var_name = plan->get_var_by_index(p_id).first; name_edit->set_text(var_name); - _name_changed(var_name); + _name_submitted(); } void EditorPropertyVariableName::_update_status() { @@ -143,7 +150,9 @@ void EditorPropertyVariableName::setup(const Ref &p_plan, bool p void EditorPropertyVariableName::_notification(int p_what) { switch (p_what) { case NOTIFICATION_READY: { - name_edit->connect(LW_NAME(text_changed), callable_mp(this, &EditorPropertyVariableName::_name_changed)); + name_edit->connect(LW_NAME(text_changed), callable_mp(this, &EditorPropertyVariableName::_name_changed).bind(true)); + name_edit->connect(LW_NAME(text_submitted), callable_mp(this, &EditorPropertyVariableName::_name_submitted).unbind(1)); + name_edit->connect(LW_NAME(focus_exited), callable_mp(this, &EditorPropertyVariableName::_name_submitted)); variables_popup->connect(LW_NAME(id_pressed), callable_mp(this, &EditorPropertyVariableName::_variable_selected)); drop_btn->connect(LW_NAME(pressed), callable_mp(this, &EditorPropertyVariableName::_show_variables_popup)); status_btn->connect(LW_NAME(pressed), callable_mp(this, &EditorPropertyVariableName::_status_pressed)); diff --git a/editor/editor_property_variable_name.h b/editor/editor_property_variable_name.h index da75eab..8cf2df8 100644 --- a/editor/editor_property_variable_name.h +++ b/editor/editor_property_variable_name.h @@ -55,7 +55,8 @@ private: PopupMenu *variables_popup; void _show_variables_popup(); - void _name_changed(const String &p_new_name); + void _name_changed(const String &p_new_name, bool p_changing); + void _name_submitted(); void _variable_selected(int p_id); void _update_status(); diff --git a/util/limbo_string_names.cpp b/util/limbo_string_names.cpp index 46595f7..be1b6f7 100644 --- a/util/limbo_string_names.cpp +++ b/util/limbo_string_names.cpp @@ -85,6 +85,7 @@ LimboStringNames::LimboStringNames() { exited = SN("exited"); favorite_tasks_changed = SN("favorite_tasks_changed"); Favorites = SN("Favorites"); + focus_exited = SN("focus_exited"); font = SN("font"); font_color = SN("font_color"); font_size = SN("font_size"); diff --git a/util/limbo_string_names.h b/util/limbo_string_names.h index 8311e06..6a7c148 100644 --- a/util/limbo_string_names.h +++ b/util/limbo_string_names.h @@ -101,6 +101,7 @@ public: StringName exited; StringName favorite_tasks_changed; StringName Favorites; + StringName focus_exited; StringName font_color; StringName font_size; StringName font; From 3cf90f938774a7feb42ece1941460086e848d0dc Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Wed, 15 May 2024 13:13:27 +0200 Subject: [PATCH 13/20] BlackboardPlan: Don't show mapping in root plans --- blackboard/blackboard_plan.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blackboard/blackboard_plan.h b/blackboard/blackboard_plan.h index 21ccbbf..222af2f 100644 --- a/blackboard/blackboard_plan.h +++ b/blackboard/blackboard_plan.h @@ -62,7 +62,7 @@ public: void set_parent_scope_plan_provider(const Callable &p_parent_scope_plan_provider); Callable get_parent_scope_plan_provider() const { return parent_scope_plan_provider; } - bool is_mapping_enabled() const { return parent_scope_plan_provider.is_valid(); } + bool is_mapping_enabled() const { return parent_scope_plan_provider.is_valid() && (parent_scope_plan_provider.call() != Ref()); } bool has_mapping(const StringName &p_name) const; void set_prefetch_nodepath_vars(bool p_enable); From 2718271bb1e7de7fe8c23e94f2d48abf47763ec7 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Wed, 15 May 2024 20:43:24 +0200 Subject: [PATCH 14/20] Clean up & renames --- blackboard/blackboard_plan.cpp | 5 ++--- editor/blackboard_plan_editor.cpp | 6 +++++- editor/blackboard_plan_editor.h | 3 ++- editor/editor_property_variable_name.cpp | 24 ++++++++++++++---------- editor/editor_property_variable_name.h | 11 ++++++----- editor/limbo_ai_editor_plugin.cpp | 2 +- 6 files changed, 30 insertions(+), 21 deletions(-) diff --git a/blackboard/blackboard_plan.cpp b/blackboard/blackboard_plan.cpp index 1720e72..acc100b 100644 --- a/blackboard/blackboard_plan.cpp +++ b/blackboard/blackboard_plan.cpp @@ -425,11 +425,10 @@ void BlackboardPlan::_bind_methods() { ClassDB::bind_method(D_METHOD("set_base_plan", "blackboard_plan"), &BlackboardPlan::set_base_plan); ClassDB::bind_method(D_METHOD("get_base_plan"), &BlackboardPlan::get_base_plan); - ClassDB::bind_method(D_METHOD("set_parent_scope_plan_provider", "callable"), &BlackboardPlan::set_parent_scope_plan_provider); - ClassDB::bind_method(D_METHOD("get_parent_scope_plan_provider"), &BlackboardPlan::get_parent_scope_plan_provider); - ClassDB::bind_method(D_METHOD("is_mapping_enabled"), &BlackboardPlan::is_mapping_enabled); ClassDB::bind_method(D_METHOD("is_derived"), &BlackboardPlan::is_derived); ClassDB::bind_method(D_METHOD("sync_with_base_plan"), &BlackboardPlan::sync_with_base_plan); + ClassDB::bind_method(D_METHOD("set_parent_scope_plan_provider", "callable"), &BlackboardPlan::set_parent_scope_plan_provider); + ClassDB::bind_method(D_METHOD("get_parent_scope_plan_provider"), &BlackboardPlan::get_parent_scope_plan_provider); ClassDB::bind_method(D_METHOD("create_blackboard", "node"), &BlackboardPlan::create_blackboard); ClassDB::bind_method(D_METHOD("populate_blackboard", "blackboard", "overwrite", "node"), &BlackboardPlan::populate_blackboard); diff --git a/editor/blackboard_plan_editor.cpp b/editor/blackboard_plan_editor.cpp index c0424b8..a33220c 100644 --- a/editor/blackboard_plan_editor.cpp +++ b/editor/blackboard_plan_editor.cpp @@ -55,6 +55,9 @@ void BlackboardPlanEditor::_add_var() { } BBVariable var(default_type, default_hint, default_hint_string); + if (default_value.get_type() == default_type) { + var.set_value(default_value); + } plan->add_var(var_name, var); reset_defaults(); _refresh(); @@ -128,11 +131,12 @@ void BlackboardPlanEditor::edit_plan(const Ref &p_plan) { _refresh(); } -void BlackboardPlanEditor::set_defaults(const StringName &p_var_name, Variant::Type p_type, PropertyHint p_hint, String p_hint_string) { +void BlackboardPlanEditor::set_defaults(const StringName &p_var_name, Variant::Type p_type, PropertyHint p_hint, String p_hint_string, Variant p_value) { default_var_name = p_var_name; default_type = p_type; default_hint = p_hint; default_hint_string = p_hint_string; + default_value = p_value; } void BlackboardPlanEditor::reset_defaults() { diff --git a/editor/blackboard_plan_editor.h b/editor/blackboard_plan_editor.h index b1609a4..a711184 100644 --- a/editor/blackboard_plan_editor.h +++ b/editor/blackboard_plan_editor.h @@ -62,6 +62,7 @@ private: Variant::Type default_type = Variant::NIL; PropertyHint default_hint = PROPERTY_HINT_NONE; String default_hint_string; + Variant default_value; VBoxContainer *rows_vbox; Button *add_var_tool; @@ -102,7 +103,7 @@ public: _FORCE_INLINE_ static BlackboardPlanEditor *get_singleton() { return singleton; } void edit_plan(const Ref &p_plan); - void set_defaults(const StringName &p_name, Variant::Type p_type = Variant::FLOAT, PropertyHint p_hint = PROPERTY_HINT_NONE, String p_hint_string = ""); + void set_defaults(const StringName &p_name, Variant::Type p_type = Variant::FLOAT, PropertyHint p_hint = PROPERTY_HINT_NONE, String p_hint_string = "", Variant p_value = Variant()); void reset_defaults(); BlackboardPlanEditor(); diff --git a/editor/editor_property_variable_name.cpp b/editor/editor_property_variable_name.cpp index 176c236..529a2d9 100644 --- a/editor/editor_property_variable_name.cpp +++ b/editor/editor_property_variable_name.cpp @@ -105,7 +105,8 @@ void EditorPropertyVariableName::_update_status() { void EditorPropertyVariableName::_status_pressed() { ERR_FAIL_NULL(plan); if (!plan->has_var(name_edit->get_text())) { - BlackboardPlanEditor::get_singleton()->set_defaults(name_edit->get_text(), expected_type, expected_hint, expected_hint_string); + BlackboardPlanEditor::get_singleton()->set_defaults(name_edit->get_text(), + expected_type, default_hint, default_hint_string, default_value); } BlackboardPlanEditor::get_singleton()->edit_plan(plan); BlackboardPlanEditor::get_singleton()->popup_centered(); @@ -138,12 +139,13 @@ void EditorPropertyVariableName::_update_property() { _update_status(); } -void EditorPropertyVariableName::setup(const Ref &p_plan, bool p_allow_empty, Variant::Type p_type, PropertyHint p_hint, String p_hint_string) { +void EditorPropertyVariableName::setup(const Ref &p_plan, bool p_allow_empty, Variant::Type p_type, PropertyHint p_hint, String p_hint_string, Variant p_default_value) { plan = p_plan; allow_empty = p_allow_empty; expected_type = p_type; - expected_hint = p_hint; - expected_hint_string = p_hint_string; + default_hint = p_hint; + default_hint_string = p_hint_string; + default_value = p_default_value; _update_status(); } @@ -238,8 +240,9 @@ bool EditorInspectorPluginVariableName::_parse_property(Object *p_object, const Ref plan; Variant::Type expected_type = Variant::NIL; - PropertyHint expected_hint = PROPERTY_HINT_NONE; - String expected_hint_string; + PropertyHint default_hint = PROPERTY_HINT_NONE; + String default_hint_string; + Variant default_value; if (is_mapping) { plan.reference_ptr(Object::cast_to(p_object)); ERR_FAIL_NULL_V(plan, false); @@ -247,8 +250,9 @@ bool EditorInspectorPluginVariableName::_parse_property(Object *p_object, const if (plan->has_var(var_name)) { BBVariable variable = plan->get_var(var_name); expected_type = variable.get_type(); - expected_hint = variable.get_hint(); - expected_hint_string = variable.get_hint_string(); + default_hint = variable.get_hint(); + default_hint_string = variable.get_hint_string(); + default_value = variable.get_value(); } if (plan->get_parent_scope_plan_provider().is_valid()) { Ref parent_plan = plan->get_parent_scope_plan_provider().call(); @@ -258,11 +262,11 @@ bool EditorInspectorPluginVariableName::_parse_property(Object *p_object, const } ERR_FAIL_NULL_V(plan, false); } else { - plan = plan_getter.call(); + plan = editor_plan_provider.call(); } EditorPropertyVariableName *ed = memnew(EditorPropertyVariableName); - ed->setup(plan, is_mapping, expected_type, expected_hint, expected_hint_string); + ed->setup(plan, is_mapping, expected_type, default_hint, default_hint_string, default_value); add_property_editor(p_path, ed, expected_type); return true; diff --git a/editor/editor_property_variable_name.h b/editor/editor_property_variable_name.h index 8cf2df8..ad57b94 100644 --- a/editor/editor_property_variable_name.h +++ b/editor/editor_property_variable_name.h @@ -46,8 +46,9 @@ private: bool allow_empty = false; Variant::Type expected_type = Variant::NIL; - PropertyHint expected_hint = PROPERTY_HINT_NONE; - String expected_hint_string; + PropertyHint default_hint = PROPERTY_HINT_NONE; + String default_hint_string; + Variant default_value; LineEdit *name_edit; Button *drop_btn; @@ -76,7 +77,7 @@ public: virtual void _update_property() override; #endif - void setup(const Ref &p_plan, bool p_allow_empty, Variant::Type p_type = Variant::FLOAT, PropertyHint p_hint = PROPERTY_HINT_NONE, String p_hint_string = ""); + void setup(const Ref &p_plan, bool p_allow_empty, Variant::Type p_type = Variant::FLOAT, PropertyHint p_hint = PROPERTY_HINT_NONE, String p_hint_string = "", Variant p_default_value = Variant()); EditorPropertyVariableName(); }; @@ -84,7 +85,7 @@ class EditorInspectorPluginVariableName : public EditorInspectorPlugin { GDCLASS(EditorInspectorPluginVariableName, EditorInspectorPlugin); private: - Callable plan_getter; + Callable editor_plan_provider; protected: static void _bind_methods() {} @@ -98,7 +99,7 @@ public: virtual bool _parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField p_usage, const bool p_wide = false) override; #endif - void set_plan_getter(const Callable &p_getter) { plan_getter = p_getter; } + void set_editor_plan_provider(const Callable &p_getter) { editor_plan_provider = p_getter; } EditorInspectorPluginVariableName() = default; }; diff --git a/editor/limbo_ai_editor_plugin.cpp b/editor/limbo_ai_editor_plugin.cpp index 82df889..09c91a0 100644 --- a/editor/limbo_ai_editor_plugin.cpp +++ b/editor/limbo_ai_editor_plugin.cpp @@ -1486,7 +1486,7 @@ void LimboAIEditorPlugin::_notification(int p_notification) { add_debugger_plugin(memnew(LimboDebuggerPlugin)); add_inspector_plugin(memnew(EditorInspectorPluginBBPlan)); EditorInspectorPluginVariableName *var_plugin = memnew(EditorInspectorPluginVariableName); - var_plugin->set_plan_getter(Callable(limbo_ai_editor, "get_edited_blackboard_plan")); + var_plugin->set_editor_plan_provider(Callable(limbo_ai_editor, "get_edited_blackboard_plan")); add_inspector_plugin(var_plugin); #ifdef LIMBOAI_MODULE // ! Only used in the module version. From d920060dee81d6edcfdc094c314cc5df25f57aab Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Wed, 15 May 2024 20:58:38 +0200 Subject: [PATCH 15/20] Update class documentation --- blackboard/blackboard_plan.cpp | 2 +- doc/source/classes/class_blackboardplan.rst | 32 +++++- doc/source/classes/class_bttask.rst | 120 +++++++++++--------- doc_classes/BTTask.xml | 6 + doc_classes/BlackboardPlan.xml | 14 +++ 5 files changed, 118 insertions(+), 56 deletions(-) diff --git a/blackboard/blackboard_plan.cpp b/blackboard/blackboard_plan.cpp index acc100b..5278cc5 100644 --- a/blackboard/blackboard_plan.cpp +++ b/blackboard/blackboard_plan.cpp @@ -429,7 +429,7 @@ void BlackboardPlan::_bind_methods() { ClassDB::bind_method(D_METHOD("sync_with_base_plan"), &BlackboardPlan::sync_with_base_plan); ClassDB::bind_method(D_METHOD("set_parent_scope_plan_provider", "callable"), &BlackboardPlan::set_parent_scope_plan_provider); ClassDB::bind_method(D_METHOD("get_parent_scope_plan_provider"), &BlackboardPlan::get_parent_scope_plan_provider); - ClassDB::bind_method(D_METHOD("create_blackboard", "node"), &BlackboardPlan::create_blackboard); + ClassDB::bind_method(D_METHOD("create_blackboard", "node", "parent_scope"), &BlackboardPlan::create_blackboard); ClassDB::bind_method(D_METHOD("populate_blackboard", "blackboard", "overwrite", "node"), &BlackboardPlan::populate_blackboard); // To avoid cluttering the member namespace, we do not export unnecessary properties in this class. diff --git a/doc/source/classes/class_blackboardplan.rst b/doc/source/classes/class_blackboardplan.rst index f19a4c7..88b2ba3 100644 --- a/doc/source/classes/class_blackboardplan.rst +++ b/doc/source/classes/class_blackboardplan.rst @@ -35,16 +35,20 @@ Methods :widths: auto +---------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | :ref:`Blackboard` | :ref:`create_blackboard` **(** Node node **)** | + | :ref:`Blackboard` | :ref:`create_blackboard` **(** Node node, :ref:`Blackboard` parent_scope **)** | +---------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | :ref:`BlackboardPlan` | :ref:`get_base_plan` **(** **)** |const| | +---------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | Callable | :ref:`get_parent_scope_plan_provider` **(** **)** |const| | + +---------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | bool | :ref:`is_derived` **(** **)** |const| | +---------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | void | :ref:`populate_blackboard` **(** :ref:`Blackboard` blackboard, bool overwrite, Node node **)** | +---------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | void | :ref:`set_base_plan` **(** :ref:`BlackboardPlan` blackboard_plan **)** | +---------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | void | :ref:`set_parent_scope_plan_provider` **(** Callable callable **)** | + +---------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | void | :ref:`sync_with_base_plan` **(** **)** | +---------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -83,7 +87,7 @@ Method Descriptions .. rst-class:: classref-method -:ref:`Blackboard` **create_blackboard** **(** Node node **)** +:ref:`Blackboard` **create_blackboard** **(** Node node, :ref:`Blackboard` parent_scope **)** Constructs a new instance of a :ref:`Blackboard` using this plan. If ``NodePath`` prefetching is enabled, ``node`` will be used to retrieve node instances for ``NodePath`` variables and substitute their values. @@ -103,6 +107,18 @@ Returns the base plan. See :ref:`is_derived` **(** **)** |virtual| | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ - | void | :ref:`_exit` **(** **)** |virtual| | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ - | String | :ref:`_generate_name` **(** **)** |virtual| |const| | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ - | PackedStringArray | :ref:`_get_configuration_warnings` **(** **)** |virtual| |const| | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ - | void | :ref:`_setup` **(** **)** |virtual| | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ - | :ref:`Status` | :ref:`_tick` **(** float delta **)** |virtual| | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ - | void | :ref:`abort` **(** **)** | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ - | void | :ref:`add_child` **(** :ref:`BTTask` task **)** | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ - | void | :ref:`add_child_at_index` **(** :ref:`BTTask` task, int idx **)** | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ - | :ref:`BTTask` | :ref:`clone` **(** **)** |const| | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ - | :ref:`Status` | :ref:`execute` **(** float delta **)** | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ - | :ref:`BTTask` | :ref:`get_child` **(** int idx **)** |const| | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ - | int | :ref:`get_child_count` **(** **)** |const| | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ - | int | :ref:`get_child_count_excluding_comments` **(** **)** |const| | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ - | int | :ref:`get_index` **(** **)** |const| | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ - | :ref:`BTTask` | :ref:`get_parent` **(** **)** |const| | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ - | :ref:`BTTask` | :ref:`get_root` **(** **)** |const| | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ - | String | :ref:`get_task_name` **(** **)** | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ - | bool | :ref:`has_child` **(** :ref:`BTTask` task **)** |const| | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ - | void | :ref:`initialize` **(** Node agent, :ref:`Blackboard` blackboard, Node scene_root **)** | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ - | bool | :ref:`is_descendant_of` **(** :ref:`BTTask` task **)** |const| | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ - | bool | :ref:`is_root` **(** **)** |const| | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ - | :ref:`BTTask` | :ref:`next_sibling` **(** **)** |const| | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ - | void | :ref:`print_tree` **(** int initial_tabs=0 **)** | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ - | void | :ref:`remove_child` **(** :ref:`BTTask` task **)** | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ - | void | :ref:`remove_child_at_index` **(** int idx **)** | - +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | void | :ref:`_enter` **(** **)** |virtual| | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | void | :ref:`_exit` **(** **)** |virtual| | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | String | :ref:`_generate_name` **(** **)** |virtual| |const| | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | PackedStringArray | :ref:`_get_configuration_warnings` **(** **)** |virtual| |const| | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | void | :ref:`_setup` **(** **)** |virtual| | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | :ref:`Status` | :ref:`_tick` **(** float delta **)** |virtual| | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | void | :ref:`abort` **(** **)** | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | void | :ref:`add_child` **(** :ref:`BTTask` task **)** | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | void | :ref:`add_child_at_index` **(** :ref:`BTTask` task, int idx **)** | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | :ref:`BTTask` | :ref:`clone` **(** **)** |const| | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | :ref:`BehaviorTree` | :ref:`editor_get_behavior_tree` **(** **)** | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | :ref:`Status` | :ref:`execute` **(** float delta **)** | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | :ref:`BTTask` | :ref:`get_child` **(** int idx **)** |const| | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | int | :ref:`get_child_count` **(** **)** |const| | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | int | :ref:`get_child_count_excluding_comments` **(** **)** |const| | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | int | :ref:`get_index` **(** **)** |const| | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | :ref:`BTTask` | :ref:`get_parent` **(** **)** |const| | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | :ref:`BTTask` | :ref:`get_root` **(** **)** |const| | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | String | :ref:`get_task_name` **(** **)** | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | bool | :ref:`has_child` **(** :ref:`BTTask` task **)** |const| | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | void | :ref:`initialize` **(** Node agent, :ref:`Blackboard` blackboard, Node scene_root **)** | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | bool | :ref:`is_descendant_of` **(** :ref:`BTTask` task **)** |const| | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | bool | :ref:`is_root` **(** **)** |const| | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | :ref:`BTTask` | :ref:`next_sibling` **(** **)** |const| | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | void | :ref:`print_tree` **(** int initial_tabs=0 **)** | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | void | :ref:`remove_child` **(** :ref:`BTTask` task **)** | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | void | :ref:`remove_child_at_index` **(** int idx **)** | + +-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ .. rst-class:: classref-section-separator @@ -366,6 +368,18 @@ Duplicates the task and its children, copying the exported members. Sub-resource ---- +.. _class_BTTask_method_editor_get_behavior_tree: + +.. rst-class:: classref-method + +:ref:`BehaviorTree` **editor_get_behavior_tree** **(** **)** + +Returns the behavior tree that owns this task. This is only available in the editor. + +.. rst-class:: classref-item-separator + +---- + .. _class_BTTask_method_execute: .. rst-class:: classref-method diff --git a/doc_classes/BTTask.xml b/doc_classes/BTTask.xml index 1c922ee..ff2085c 100644 --- a/doc_classes/BTTask.xml +++ b/doc_classes/BTTask.xml @@ -79,6 +79,12 @@ Duplicates the task and its children, copying the exported members. Sub-resources are shared for efficiency, except for [BBParam] subtypes, which are always copied. Used by the editor to instantiate [BehaviorTree] and copy-paste tasks. + + + + Returns the behavior tree that owns this task. This is only available in the editor. + + diff --git a/doc_classes/BlackboardPlan.xml b/doc_classes/BlackboardPlan.xml index 2be4080..5e3fe24 100644 --- a/doc_classes/BlackboardPlan.xml +++ b/doc_classes/BlackboardPlan.xml @@ -11,6 +11,7 @@ + Constructs a new instance of a [Blackboard] using this plan. If [NodePath] prefetching is enabled, [param node] will be used to retrieve node instances for [NodePath] variables and substitute their values. @@ -21,6 +22,12 @@ Returns the base plan. See [method is_derived]. + + + + Returns the parent scope plan provider - a callable that returns a [BlackboardPlan]. + + @@ -44,6 +51,13 @@ Use with caution, as it will remove variables not present in the base plan. Only use this for custom tooling. + + + + + Sets the parent scope plan provider - a callable that returns a [BlackboardPlan]. Used to provide hints in the inspector. When set, mapping feature becomes available. + + From d08018b7b1b5e67c8d407d23ffd6bde704166117 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Fri, 17 May 2024 10:00:12 +0200 Subject: [PATCH 16/20] BlackboardPlan: Update mapping after variable renamed Currently, only for owned variables, not parent's. --- blackboard/blackboard_plan.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/blackboard/blackboard_plan.cpp b/blackboard/blackboard_plan.cpp index 5278cc5..5873bb0 100644 --- a/blackboard/blackboard_plan.cpp +++ b/blackboard/blackboard_plan.cpp @@ -273,6 +273,11 @@ void BlackboardPlan::rename_var(const StringName &p_name, const StringName &p_ne var_map.erase(p_name); var_map.insert(p_new_name, var); + if (parent_scope_mapping.has(p_name)) { + parent_scope_mapping[p_new_name] = parent_scope_mapping[p_name]; + parent_scope_mapping.erase(p_name); + } + notify_property_list_changed(); emit_changed(); } From 026272f7f70faa418b0ab7b7b2b4e54186d3194e Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Fri, 17 May 2024 10:27:22 +0200 Subject: [PATCH 17/20] Fix BBParam subtypes incorrectly display type error in inspector --- editor/editor_property_variable_name.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/editor_property_variable_name.h b/editor/editor_property_variable_name.h index ad57b94..0ea1a55 100644 --- a/editor/editor_property_variable_name.h +++ b/editor/editor_property_variable_name.h @@ -77,7 +77,7 @@ public: virtual void _update_property() override; #endif - void setup(const Ref &p_plan, bool p_allow_empty, Variant::Type p_type = Variant::FLOAT, PropertyHint p_hint = PROPERTY_HINT_NONE, String p_hint_string = "", Variant p_default_value = Variant()); + void setup(const Ref &p_plan, bool p_allow_empty, Variant::Type p_type = Variant::NIL, PropertyHint p_hint = PROPERTY_HINT_NONE, String p_hint_string = "", Variant p_default_value = Variant()); EditorPropertyVariableName(); }; From dc77ecd2b28ec790bb0e817b2b6b74b30aed9c81 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Fri, 17 May 2024 10:36:25 +0200 Subject: [PATCH 18/20] Fix `parent_scope` argument in `create_blackboard` should have a default value --- blackboard/blackboard_plan.cpp | 2 +- doc/source/classes/class_blackboardplan.rst | 4 ++-- doc_classes/BlackboardPlan.xml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/blackboard/blackboard_plan.cpp b/blackboard/blackboard_plan.cpp index 5873bb0..b49b4e0 100644 --- a/blackboard/blackboard_plan.cpp +++ b/blackboard/blackboard_plan.cpp @@ -434,7 +434,7 @@ void BlackboardPlan::_bind_methods() { ClassDB::bind_method(D_METHOD("sync_with_base_plan"), &BlackboardPlan::sync_with_base_plan); ClassDB::bind_method(D_METHOD("set_parent_scope_plan_provider", "callable"), &BlackboardPlan::set_parent_scope_plan_provider); ClassDB::bind_method(D_METHOD("get_parent_scope_plan_provider"), &BlackboardPlan::get_parent_scope_plan_provider); - ClassDB::bind_method(D_METHOD("create_blackboard", "node", "parent_scope"), &BlackboardPlan::create_blackboard); + ClassDB::bind_method(D_METHOD("create_blackboard", "node", "parent_scope"), &BlackboardPlan::create_blackboard, DEFVAL(Ref())); ClassDB::bind_method(D_METHOD("populate_blackboard", "blackboard", "overwrite", "node"), &BlackboardPlan::populate_blackboard); // To avoid cluttering the member namespace, we do not export unnecessary properties in this class. diff --git a/doc/source/classes/class_blackboardplan.rst b/doc/source/classes/class_blackboardplan.rst index 88b2ba3..cb66121 100644 --- a/doc/source/classes/class_blackboardplan.rst +++ b/doc/source/classes/class_blackboardplan.rst @@ -35,7 +35,7 @@ Methods :widths: auto +---------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | :ref:`Blackboard` | :ref:`create_blackboard` **(** Node node, :ref:`Blackboard` parent_scope **)** | + | :ref:`Blackboard` | :ref:`create_blackboard` **(** Node node, :ref:`Blackboard` parent_scope=null **)** | +---------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | :ref:`BlackboardPlan` | :ref:`get_base_plan` **(** **)** |const| | +---------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -87,7 +87,7 @@ Method Descriptions .. rst-class:: classref-method -:ref:`Blackboard` **create_blackboard** **(** Node node, :ref:`Blackboard` parent_scope **)** +:ref:`Blackboard` **create_blackboard** **(** Node node, :ref:`Blackboard` parent_scope=null **)** Constructs a new instance of a :ref:`Blackboard` using this plan. If ``NodePath`` prefetching is enabled, ``node`` will be used to retrieve node instances for ``NodePath`` variables and substitute their values. diff --git a/doc_classes/BlackboardPlan.xml b/doc_classes/BlackboardPlan.xml index 5e3fe24..80de4d5 100644 --- a/doc_classes/BlackboardPlan.xml +++ b/doc_classes/BlackboardPlan.xml @@ -11,7 +11,7 @@ - + Constructs a new instance of a [Blackboard] using this plan. If [NodePath] prefetching is enabled, [param node] will be used to retrieve node instances for [NodePath] variables and substitute their values. From b54f3696fffd0a4fa4d1c4e1d519152e734222f8 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Fri, 17 May 2024 11:08:58 +0200 Subject: [PATCH 19/20] Fix crash upon adding variable in the plan editor with empty default name Also default to float when expected type is not specified. --- editor/blackboard_plan_editor.cpp | 2 +- editor/editor_property_variable_name.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/editor/blackboard_plan_editor.cpp b/editor/blackboard_plan_editor.cpp index a33220c..afdb5bf 100644 --- a/editor/blackboard_plan_editor.cpp +++ b/editor/blackboard_plan_editor.cpp @@ -48,7 +48,7 @@ void BlackboardPlanEditor::_add_var() { ERR_FAIL_NULL(plan); int suffix = 1; - StringName var_name = default_var_name; + StringName var_name = default_var_name == StringName() ? "var" : default_var_name; while (plan->has_var(var_name)) { suffix += 1; var_name = String(default_var_name) + itos(suffix); diff --git a/editor/editor_property_variable_name.cpp b/editor/editor_property_variable_name.cpp index 529a2d9..9975930 100644 --- a/editor/editor_property_variable_name.cpp +++ b/editor/editor_property_variable_name.cpp @@ -106,7 +106,8 @@ void EditorPropertyVariableName::_status_pressed() { ERR_FAIL_NULL(plan); if (!plan->has_var(name_edit->get_text())) { BlackboardPlanEditor::get_singleton()->set_defaults(name_edit->get_text(), - expected_type, default_hint, default_hint_string, default_value); + expected_type == Variant::NIL ? Variant::FLOAT : expected_type, + default_hint, default_hint_string, default_value); } BlackboardPlanEditor::get_singleton()->edit_plan(plan); BlackboardPlanEditor::get_singleton()->popup_centered(); From 7ab7a9d09834726404f2fa51cfc12c3154c9dd37 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Fri, 17 May 2024 21:48:34 +0200 Subject: [PATCH 20/20] BlackboardPlan: Improve inspector update while manually typing in mappings Fixes property glitches observed while a map variable is typed in. --- blackboard/blackboard_plan.cpp | 13 +++++++++++-- editor/editor_property_variable_name.cpp | 20 ++++++++++++++++---- editor/editor_property_variable_name.h | 7 ++++++- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/blackboard/blackboard_plan.cpp b/blackboard/blackboard_plan.cpp index b49b4e0..6d9c7ff 100644 --- a/blackboard/blackboard_plan.cpp +++ b/blackboard/blackboard_plan.cpp @@ -31,12 +31,21 @@ bool BlackboardPlan::_set(const StringName &p_name, const Variant &p_value) { if (name_str.begins_with("mapping/")) { StringName mapped_var_name = name_str.get_slicec('/', 1); StringName value = p_value; + bool properties_changed = false; if (value == StringName()) { - parent_scope_mapping.erase(mapped_var_name); + if (parent_scope_mapping.has(mapped_var_name)) { + properties_changed = true; + parent_scope_mapping.erase(mapped_var_name); + } } else { + if (!parent_scope_mapping.has(mapped_var_name)) { + properties_changed = true; + } parent_scope_mapping[mapped_var_name] = value; } - notify_property_list_changed(); + if (properties_changed) { + notify_property_list_changed(); + } return true; } diff --git a/editor/editor_property_variable_name.cpp b/editor/editor_property_variable_name.cpp index 9975930..0c40293 100644 --- a/editor/editor_property_variable_name.cpp +++ b/editor/editor_property_variable_name.cpp @@ -31,6 +31,8 @@ #include #endif // LIMBOAI_GDEXTENSION +int EditorPropertyVariableName::last_caret_column = 0; + //***** EditorPropertyVariableName void EditorPropertyVariableName::_show_variables_popup() { @@ -54,13 +56,18 @@ void EditorPropertyVariableName::_show_variables_popup() { variables_popup->popup(rect); } -void EditorPropertyVariableName::_name_changed(const String &p_new_name, bool p_changing) { - emit_changed(get_edited_property(), p_new_name, StringName(), p_changing); +void EditorPropertyVariableName::_name_changed(const String &p_new_name) { + if (updating) { + return; + } + + emit_changed(get_edited_property(), p_new_name); + last_caret_column = name_edit->get_caret_column(); _update_status(); } void EditorPropertyVariableName::_name_submitted() { - _name_changed(name_edit->get_text(), false); + _name_changed(name_edit->get_text()); if (name_edit->has_focus()) { name_edit->release_focus(); } @@ -131,13 +138,18 @@ void EditorPropertyVariableName::update_property() { void EditorPropertyVariableName::_update_property() { #endif // LIMBOAI_GDEXTENSION String s = get_edited_object()->get(get_edited_property()); + updating = true; if (name_edit->get_text() != s) { int caret = name_edit->get_caret_column(); + if (caret == 0) { + caret = last_caret_column; + } name_edit->set_text(s); name_edit->set_caret_column(caret); } name_edit->set_editable(!is_read_only()); _update_status(); + updating = false; } void EditorPropertyVariableName::setup(const Ref &p_plan, bool p_allow_empty, Variant::Type p_type, PropertyHint p_hint, String p_hint_string, Variant p_default_value) { @@ -153,7 +165,7 @@ void EditorPropertyVariableName::setup(const Ref &p_plan, bool p void EditorPropertyVariableName::_notification(int p_what) { switch (p_what) { case NOTIFICATION_READY: { - name_edit->connect(LW_NAME(text_changed), callable_mp(this, &EditorPropertyVariableName::_name_changed).bind(true)); + name_edit->connect(LW_NAME(text_changed), callable_mp(this, &EditorPropertyVariableName::_name_changed)); name_edit->connect(LW_NAME(text_submitted), callable_mp(this, &EditorPropertyVariableName::_name_submitted).unbind(1)); name_edit->connect(LW_NAME(focus_exited), callable_mp(this, &EditorPropertyVariableName::_name_submitted)); variables_popup->connect(LW_NAME(id_pressed), callable_mp(this, &EditorPropertyVariableName::_variable_selected)); diff --git a/editor/editor_property_variable_name.h b/editor/editor_property_variable_name.h index 0ea1a55..bff47a9 100644 --- a/editor/editor_property_variable_name.h +++ b/editor/editor_property_variable_name.h @@ -31,6 +31,9 @@ using namespace godot; class EditorPropertyVariableName : public EditorProperty { GDCLASS(EditorPropertyVariableName, EditorProperty); +private: + static int last_caret_column; + private: struct ThemeCache { Ref var_add_icon; @@ -50,13 +53,15 @@ private: String default_hint_string; Variant default_value; + bool updating = false; + LineEdit *name_edit; Button *drop_btn; Button *status_btn; PopupMenu *variables_popup; void _show_variables_popup(); - void _name_changed(const String &p_new_name, bool p_changing); + void _name_changed(const String &p_new_name); void _name_submitted(); void _variable_selected(int p_id); void _update_status();