From 35f2c3c142df50bac50b2966b106dac6fefd3d1f Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Fri, 31 May 2024 09:56:45 +0200 Subject: [PATCH 1/3] API: Add `Blackboard` methods to enable iteration, state inspection and serialization --- blackboard/blackboard.cpp | 34 +++++++++++++++ blackboard/blackboard.h | 7 +++- doc/source/classes/class_blackboard.rst | 56 +++++++++++++++++++++++++ doc_classes/Blackboard.xml | 25 +++++++++++ 4 files changed, 120 insertions(+), 2 deletions(-) diff --git a/blackboard/blackboard.cpp b/blackboard/blackboard.cpp index 4819013..5d15bd1 100644 --- a/blackboard/blackboard.cpp +++ b/blackboard/blackboard.cpp @@ -64,6 +64,36 @@ void Blackboard::erase_var(const StringName &p_name) { data.erase(p_name); } +TypedArray Blackboard::list_vars() const { + TypedArray var_names; + var_names.resize(data.size()); + int idx = 0; + for (const KeyValue &kv : data) { + var_names[idx] = kv.key; + idx += 1; + } + return var_names; +} + +Dictionary Blackboard::get_vars_as_dict() const { + Dictionary dict; + for (const KeyValue &kv : data) { + dict[kv.key] = kv.value.get_value(); + } + return dict; +} + +void Blackboard::populate_from_dict(const Dictionary &p_dictionary) { + Array keys = p_dictionary.keys(); + for (int i = 0; i < keys.size(); i++) { + if (keys[i].get_type() == Variant::STRING_NAME || keys[i].get_type() == Variant::STRING) { + set_var(keys[i], p_dictionary[keys[i]]); + } else { + ERR_PRINT("Blackboard: Invalid key type in dictionary to populate blackboard. Must be StringName or String."); + } + } +} + void Blackboard::bind_var_to_property(const StringName &p_name, Object *p_object, const StringName &p_property, bool p_create) { if (!data.has(p_name)) { if (p_create) { @@ -104,6 +134,10 @@ void Blackboard::_bind_methods() { ClassDB::bind_method(D_METHOD("set_parent", "blackboard"), &Blackboard::set_parent); ClassDB::bind_method(D_METHOD("get_parent"), &Blackboard::get_parent); ClassDB::bind_method(D_METHOD("erase_var", "var_name"), &Blackboard::erase_var); + ClassDB::bind_method(D_METHOD("clear"), &Blackboard::clear); + ClassDB::bind_method(D_METHOD("list_vars"), &Blackboard::list_vars); + ClassDB::bind_method(D_METHOD("get_vars_as_dict"), &Blackboard::get_vars_as_dict); + ClassDB::bind_method(D_METHOD("populate_from_dict", "dictionary"), &Blackboard::populate_from_dict); ClassDB::bind_method(D_METHOD("top"), &Blackboard::top); ClassDB::bind_method(D_METHOD("bind_var_to_property", "var_name", "object", "property", "create"), &Blackboard::bind_var_to_property, DEFVAL(false)); ClassDB::bind_method(D_METHOD("unbind_var", "var_name"), &Blackboard::unbind_var); diff --git a/blackboard/blackboard.h b/blackboard/blackboard.h index 83d8ee8..5e60ed7 100644 --- a/blackboard/blackboard.h +++ b/blackboard/blackboard.h @@ -50,6 +50,11 @@ public: void set_var(const StringName &p_name, const Variant &p_value); bool has_var(const StringName &p_name) const; void erase_var(const StringName &p_name); + void clear() { data.clear(); } + TypedArray list_vars() const; + + Dictionary get_vars_as_dict() const; + void populate_from_dict(const Dictionary &p_dictionary); void bind_var_to_property(const StringName &p_name, Object *p_object, const StringName &p_property, bool p_create = false); void unbind_var(const StringName &p_name); @@ -57,8 +62,6 @@ public: void assign_var(const StringName &p_name, const BBVariable &p_var); void link_var(const StringName &p_name, const Ref &p_target_blackboard, const StringName &p_target_var, bool p_create = false); - - // TODO: Add serialization API. }; #endif // BLACKBOARD_H diff --git a/doc/source/classes/class_blackboard.rst b/doc/source/classes/class_blackboard.rst index 824480f..227eb97 100644 --- a/doc/source/classes/class_blackboard.rst +++ b/doc/source/classes/class_blackboard.rst @@ -36,16 +36,24 @@ Methods +-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | void | :ref:`bind_var_to_property` **(** StringName var_name, Object object, StringName property, bool create=false **)** | +-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | void | :ref:`clear` **(** **)** | + +-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | void | :ref:`erase_var` **(** StringName var_name **)** | +-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | :ref:`Blackboard` | :ref:`get_parent` **(** **)** |const| | +-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Variant | :ref:`get_var` **(** StringName var_name, Variant default=null, bool complain=true **)** |const| | +-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | Dictionary | :ref:`get_vars_as_dict` **(** **)** |const| | + +-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | bool | :ref:`has_var` **(** StringName var_name **)** |const| | +-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | void | :ref:`link_var` **(** StringName var_name, :ref:`Blackboard` target_blackboard, StringName target_var, bool create=false **)** | +-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | StringName[] | :ref:`list_vars` **(** **)** |const| | + +-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | void | :ref:`populate_from_dict` **(** Dictionary dictionary **)** | + +-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | void | :ref:`set_parent` **(** :ref:`Blackboard` blackboard **)** | +-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | void | :ref:`set_var` **(** StringName var_name, Variant value **)** | @@ -76,6 +84,18 @@ Establish a binding between a variable and the object's property specified by `` ---- +.. _class_Blackboard_method_clear: + +.. rst-class:: classref-method + +void **clear** **(** **)** + +Removes all variables from the Blackboard. Parent scopes are not affected. + +.. rst-class:: classref-item-separator + +---- + .. _class_Blackboard_method_erase_var: .. rst-class:: classref-method @@ -112,6 +132,18 @@ Returns variable value or ``default`` if variable doesn't exist. If ``complain`` ---- +.. _class_Blackboard_method_get_vars_as_dict: + +.. rst-class:: classref-method + +Dictionary **get_vars_as_dict** **(** **)** |const| + +Returns all variables in the Blackboard as a dictionary. Keys are the variable names, values are the variable values. Parent scopes are not included. + +.. rst-class:: classref-item-separator + +---- + .. _class_Blackboard_method_has_var: .. rst-class:: classref-method @@ -138,6 +170,30 @@ You can use this method to link a variable in the current scope to a variable in ---- +.. _class_Blackboard_method_list_vars: + +.. rst-class:: classref-method + +StringName[] **list_vars** **(** **)** |const| + +Returns all variable names in the Blackboard. Parent scopes are not included. + +.. rst-class:: classref-item-separator + +---- + +.. _class_Blackboard_method_populate_from_dict: + +.. rst-class:: classref-method + +void **populate_from_dict** **(** Dictionary dictionary **)** + +Fills the Blackboard with multiple variables from a dictionary. The dictionary keys must be variable names and the dictionary values must be variable values. Keys must be StringName or String. + +.. rst-class:: classref-item-separator + +---- + .. _class_Blackboard_method_set_parent: .. rst-class:: classref-method diff --git a/doc_classes/Blackboard.xml b/doc_classes/Blackboard.xml index bde4856..32a0720 100644 --- a/doc_classes/Blackboard.xml +++ b/doc_classes/Blackboard.xml @@ -21,6 +21,12 @@ Establish a binding between a variable and the object's property specified by [param property] and [param object]. Changes to the variable update the property, and vice versa. If [param create] is [code]true[/code], the variable will be created if it doesn't exist. + + + + Removes all variables from the Blackboard. Parent scopes are not affected. + + @@ -43,6 +49,12 @@ Returns variable value or [param default] if variable doesn't exist. If [param complain] is [code]true[/code], an error will be printed if variable doesn't exist. + + + + Returns all variables in the Blackboard as a dictionary. Keys are the variable names, values are the variable values. Parent scopes are not included. + + @@ -61,6 +73,19 @@ You can use this method to link a variable in the current scope to a variable in another scope, or in another Blackboard instance. A variable can only be linked to one other variable. Calling this method again will overwrite the previous link. However, it is possible to link to the same variable from multiple different variables. + + + + Returns all variable names in the Blackboard. Parent scopes are not included. + + + + + + + Fills the Blackboard with multiple variables from a dictionary. The dictionary keys must be variable names and the dictionary values must be variable values. Keys must be StringName or String. + + From 1e6c3fa92b1cbb385bab7239a9d8449d9058fc89 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Fri, 31 May 2024 09:58:17 +0200 Subject: [PATCH 2/3] Files reformatted by pre-commit --- SCsub | 1 + gdextension/SConstruct | 1 + limboai_version.py | 9 +++++++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/SCsub b/SCsub index 3a95934..fbcbaed 100644 --- a/SCsub +++ b/SCsub @@ -8,6 +8,7 @@ module_env = env.Clone() module_env.Append(CPPDEFINES=["LIMBOAI_MODULE"]) import limboai_version + limboai_version.generate_module_version_header() module_env.add_source_files(env.modules_sources, "*.cpp") diff --git a/gdextension/SConstruct b/gdextension/SConstruct index 83575a0..f9a6465 100644 --- a/gdextension/SConstruct +++ b/gdextension/SConstruct @@ -15,6 +15,7 @@ env = SConscript("godot-cpp/SConstruct") # Generate version header. sys.path.append("./limboai") import limboai_version + os.chdir("./limboai") limboai_version.generate_module_version_header() os.chdir("..") diff --git a/limboai_version.py b/limboai_version.py index c7a3f03..c5562d5 100644 --- a/limboai_version.py +++ b/limboai_version.py @@ -8,8 +8,10 @@ doc_branch = "latest" # Code that generates version header + def _git_hash(short: bool = False): import subprocess + ret = "unknown" try: if short: @@ -31,7 +33,7 @@ def _get_version_info(): "status": status, "doc_branch": doc_branch, "git_short_hash": _git_hash(short=True), - "git_hash": _git_hash(short=False) + "git_hash": _git_hash(short=False), } @@ -55,5 +57,8 @@ def generate_module_version_header(): #define LIMBOAI_VERSION_DOC_URL "https://limboai.readthedocs.io/en/" LIMBOAI_VERSION_DOC_BRANCH "/" #endif // LIMBOAI_VERSION_GEN_H -""".format(**version_info)) +""".format( + **version_info + ) + ) f.close() From 29532113c06d39dd5e7b3ce234cf14bf5e7c8e69 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Fri, 31 May 2024 11:57:27 +0200 Subject: [PATCH 3/3] Change to typed array in `BlackboardPlan::list_vars` --- blackboard/blackboard_plan.cpp | 4 ++-- blackboard/blackboard_plan.h | 2 +- editor/blackboard_plan_editor.cpp | 20 +++++++++----------- editor/editor_property_variable_name.cpp | 7 +++---- 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/blackboard/blackboard_plan.cpp b/blackboard/blackboard_plan.cpp index 6d9c7ff..25ddf9e 100644 --- a/blackboard/blackboard_plan.cpp +++ b/blackboard/blackboard_plan.cpp @@ -240,8 +240,8 @@ Pair BlackboardPlan::get_var_by_index(int p_index) { return var_list[p_index]; } -PackedStringArray BlackboardPlan::list_vars() const { - PackedStringArray ret; +TypedArray BlackboardPlan::list_vars() const { + TypedArray ret; for (const Pair &p : var_list) { ret.append(p.first); } diff --git a/blackboard/blackboard_plan.h b/blackboard/blackboard_plan.h index 222af2f..c58fb21 100644 --- a/blackboard/blackboard_plan.h +++ b/blackboard/blackboard_plan.h @@ -76,7 +76,7 @@ public: _FORCE_INLINE_ bool is_empty() const { return var_map.is_empty(); } int get_var_count() const { return var_map.size(); } - PackedStringArray list_vars() const; + TypedArray list_vars() const; StringName get_var_name(const BBVariable &p_var) const; bool is_valid_var_name(const StringName &p_name) const; void rename_var(const StringName &p_name, const StringName &p_new_name); diff --git a/editor/blackboard_plan_editor.cpp b/editor/blackboard_plan_editor.cpp index afdb5bf..82333d2 100644 --- a/editor/blackboard_plan_editor.cpp +++ b/editor/blackboard_plan_editor.cpp @@ -260,14 +260,14 @@ void BlackboardPlanEditor::_refresh() { nodepath_prefetching->set_pressed(plan->is_prefetching_nodepath_vars()); - PackedStringArray names = plan->list_vars(); - int idx = 0; - for (const String &var_name : names) { + TypedArray names = plan->list_vars(); + for (int i = 0; i < names.size(); i++) { + const String &var_name = names[i]; BBVariable var = plan->get_var(var_name); PanelContainer *row_panel = memnew(PanelContainer); rows_vbox->add_child(row_panel); - ADD_STYLEBOX_OVERRIDE(row_panel, LW_NAME(panel), idx % 2 ? theme_cache.odd_style : theme_cache.even_style); + ADD_STYLEBOX_OVERRIDE(row_panel, LW_NAME(panel), i % 2 ? theme_cache.odd_style : theme_cache.even_style); row_panel->set_h_size_flags(Control::SIZE_EXPAND_FILL); HBoxContainer *props_hbox = memnew(HBoxContainer); @@ -288,7 +288,7 @@ void BlackboardPlanEditor::_refresh() { name_edit->set_placeholder(TTR("Variable name")); name_edit->set_flat(true); name_edit->set_custom_minimum_size(Size2(300.0, 0.0) * EDSCALE); - name_edit->connect(LW_NAME(text_changed), callable_mp(this, &BlackboardPlanEditor::_rename_var).bind(idx)); + name_edit->connect(LW_NAME(text_changed), callable_mp(this, &BlackboardPlanEditor::_rename_var).bind(i)); name_edit->connect(LW_NAME(text_submitted), callable_mp(this, &BlackboardPlanEditor::_refresh).unbind(1)); Button *type_choice = memnew(Button); @@ -300,7 +300,7 @@ void BlackboardPlanEditor::_refresh() { type_choice->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS); type_choice->set_flat(true); type_choice->set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT); - type_choice->connect(LW_NAME(pressed), callable_mp(this, &BlackboardPlanEditor::_show_button_popup).bind(type_choice, type_menu, idx)); + type_choice->connect(LW_NAME(pressed), callable_mp(this, &BlackboardPlanEditor::_show_button_popup).bind(type_choice, type_menu, i)); Button *hint_choice = memnew(Button); props_hbox->add_child(hint_choice); @@ -310,7 +310,7 @@ void BlackboardPlanEditor::_refresh() { hint_choice->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS); hint_choice->set_flat(true); hint_choice->set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT); - hint_choice->connect(LW_NAME(pressed), callable_mp(this, &BlackboardPlanEditor::_show_button_popup).bind(hint_choice, hint_menu, idx)); + hint_choice->connect(LW_NAME(pressed), callable_mp(this, &BlackboardPlanEditor::_show_button_popup).bind(hint_choice, hint_menu, i)); LineEdit *hint_string_edit = memnew(LineEdit); props_hbox->add_child(hint_string_edit); @@ -319,16 +319,14 @@ void BlackboardPlanEditor::_refresh() { hint_string_edit->set_placeholder(TTR("Hint string")); hint_string_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL); hint_string_edit->set_flat(true); - hint_string_edit->connect(LW_NAME(text_changed), callable_mp(this, &BlackboardPlanEditor::_change_var_hint_string).bind(idx)); + hint_string_edit->connect(LW_NAME(text_changed), callable_mp(this, &BlackboardPlanEditor::_change_var_hint_string).bind(i)); hint_string_edit->connect(LW_NAME(text_submitted), callable_mp(this, &BlackboardPlanEditor::_refresh).unbind(1)); Button *trash_button = memnew(Button); props_hbox->add_child(trash_button); trash_button->set_custom_minimum_size(Size2(24.0, 0.0) * EDSCALE); BUTTON_SET_ICON(trash_button, theme_cache.trash_icon); - trash_button->connect(LW_NAME(pressed), callable_mp(this, &BlackboardPlanEditor::_trash_var).bind(idx)); - - idx += 1; + trash_button->connect(LW_NAME(pressed), callable_mp(this, &BlackboardPlanEditor::_trash_var).bind(i)); } } diff --git a/editor/editor_property_variable_name.cpp b/editor/editor_property_variable_name.cpp index ad3cb69..44c11f8 100644 --- a/editor/editor_property_variable_name.cpp +++ b/editor/editor_property_variable_name.cpp @@ -40,10 +40,9 @@ void EditorPropertyVariableName::_show_variables_popup() { variables_popup->clear(); variables_popup->reset_size(); - int idx = 0; - for (String var_name : plan->list_vars()) { - variables_popup->add_item(var_name, idx); - idx += 1; + TypedArray var_names = plan->list_vars(); + for (int i = 0; i < var_names.size(); i++) { + variables_popup->add_item(var_names[i], i); } Transform2D xform = name_edit->get_screen_transform();