diff --git a/blackboard/bb_variable.cpp b/blackboard/bb_variable.cpp index fda7c80..12ad83b 100644 --- a/blackboard/bb_variable.cpp +++ b/blackboard/bb_variable.cpp @@ -11,6 +11,8 @@ #include "bb_variable.h" +#include "../util/limbo_compat.h" + void BBVariable::unref() { if (data && data->refcount.unref()) { memdelete(data); @@ -36,6 +38,7 @@ Variant BBVariable::get_value() const { void BBVariable::set_type(Variant::Type p_type) { data->type = p_type; + data->value = VARIANT_DEFAULT(p_type); } Variant::Type BBVariable::get_type() const { @@ -136,9 +139,13 @@ BBVariable::BBVariable(const BBVariable &p_var) { } } -BBVariable::BBVariable() { +BBVariable::BBVariable(Variant::Type p_type, PropertyHint p_hint, const String &p_hint_string) { data = memnew(Data); data->refcount.init(); + + set_type(p_type); + data->hint = p_hint; + data->hint_string = p_hint_string; } BBVariable::~BBVariable() { diff --git a/blackboard/bb_variable.h b/blackboard/bb_variable.h index d5b2fc3..d6d2371 100644 --- a/blackboard/bb_variable.h +++ b/blackboard/bb_variable.h @@ -14,6 +14,7 @@ #include "core/object/object.h" #include "core/templates/safe_refcount.h" +#include "core/variant/variant.h" class BBVariable { private: @@ -60,7 +61,7 @@ public: void operator=(const BBVariable &p_var); BBVariable(const BBVariable &p_var); - BBVariable(); + BBVariable(Variant::Type p_type = Variant::Type::NIL, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = ""); ~BBVariable(); }; diff --git a/blackboard/blackboard_source.cpp b/blackboard/blackboard_source.cpp index 08cfb96..9d1b718 100644 --- a/blackboard/blackboard_source.cpp +++ b/blackboard/blackboard_source.cpp @@ -11,6 +11,93 @@ #include "blackboard_source.h" +bool BlackboardSource::_set(const StringName &p_name, const Variant &p_value) { + String prop_name = p_name; + + // * Editor + if (data.has(prop_name)) { + data[prop_name].set_value(p_value); + return true; + } + + // * Storage + if (prop_name.begins_with("var/")) { + String var_name = prop_name.get_slicec('/', 1); + String what = prop_name.get_slicec('/', 2); + if (!data.has(var_name) && what == "name") { + data.insert(var_name, BBVariable()); + } + if (what == "name") { + // We don't store variable name with the variable. + } else if (what == "type") { + data[var_name].set_type((Variant::Type)(int)p_value); + } else if (what == "value") { + data[var_name].set_value(p_value); + } else if (what == "hint") { + data[var_name].set_hint((PropertyHint)(int)p_value); + } else if (what == "hint_string") { + data[var_name].set_hint_string(p_value); + } else { + return false; + } + return true; + } + + return false; +} + +bool BlackboardSource::_get(const StringName &p_name, Variant &r_ret) const { + String prop_name = p_name; + + // * Editor + if (data.has(prop_name)) { + r_ret = data[prop_name].get_value(); + return true; + } + + // * Storage + if (!prop_name.begins_with("var/")) { + return false; + } + + String var_name = prop_name.get_slicec('/', 1); + String what = prop_name.get_slicec('/', 2); + ERR_FAIL_COND_V(!data.has(var_name), false); + if (what == "type") { + r_ret = data[var_name].get_type(); + } else if (what == "value") { + r_ret = data[var_name].get_value(); + } else if (what == "hint") { + r_ret = data[var_name].get_hint(); + } else if (what == "hint_string") { + r_ret = data[var_name].get_hint_string(); + } + return true; +} + +void BlackboardSource::_get_property_list(List *p_list) const { + for (const KeyValue &kv : data) { + String var_name = kv.key; + BBVariable var = kv.value; + + // * Editor + p_list->push_back(PropertyInfo(var.get_type(), var_name, var.get_hint(), var.get_hint_string(), PROPERTY_USAGE_EDITOR)); + + // * 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)); + } +} + +void BlackboardSource::set_base_source(const Ref &p_base) { + base = p_base; + sync_base(); + emit_changed(); +} + void BlackboardSource::set_value(const String &p_name, const Variant &p_value) { ERR_FAIL_COND(!data.has(p_name)); data.get(p_name).set_value(p_value); @@ -83,3 +170,10 @@ void BlackboardSource::populate_blackboard(const Ref &p_blackboard, p_blackboard->add_var(kv.key, kv.value.duplicate()); } } + +BlackboardSource::BlackboardSource() { + // TODO: REMOVE ALL BELOW + data.insert("speed", BBVariable(Variant::Type::FLOAT, PropertyHint::PROPERTY_HINT_NONE, "")); + data.insert("limit_speed", BBVariable(Variant::Type::BOOL, PropertyHint::PROPERTY_HINT_NONE, "")); + data.insert("about", BBVariable(Variant::Type::STRING, PropertyHint::PROPERTY_HINT_MULTILINE_TEXT, "")); +} diff --git a/blackboard/blackboard_source.h b/blackboard/blackboard_source.h index 38b4b5c..56eaf9c 100644 --- a/blackboard/blackboard_source.h +++ b/blackboard/blackboard_source.h @@ -25,7 +25,15 @@ private: Ref base; // HashMap overrides; +protected: + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List *p_list) const; + public: + void set_base_source(const Ref &p_base); + Ref get_base_source() const { return base; } + void set_value(const String &p_name, const Variant &p_value); Variant get_value(const String &p_name) const; void add_var(const String &p_name, const BBVariable &p_var); @@ -38,7 +46,7 @@ public: Ref create_blackboard(); void populate_blackboard(const Ref &p_blackboard, bool overwrite); - BlackboardSource() = default; + BlackboardSource(); }; #endif // BLACKBOARD_SOURCE_H diff --git a/bt/behavior_tree.cpp b/bt/behavior_tree.cpp index b6fc0d9..5508b6d 100644 --- a/bt/behavior_tree.cpp +++ b/bt/behavior_tree.cpp @@ -47,6 +47,8 @@ Ref BehaviorTree::instantiate(Node *p_agent, const Ref &p_bl void BehaviorTree::_bind_methods() { ClassDB::bind_method(D_METHOD("set_description", "p_value"), &BehaviorTree::set_description); ClassDB::bind_method(D_METHOD("get_description"), &BehaviorTree::get_description); + ClassDB::bind_method(D_METHOD("set_blackboard_source", "p_source"), &BehaviorTree::set_blackboard_source); + ClassDB::bind_method(D_METHOD("get_blackboard_source"), &BehaviorTree::get_blackboard_source); ClassDB::bind_method(D_METHOD("set_root_task", "p_value"), &BehaviorTree::set_root_task); ClassDB::bind_method(D_METHOD("get_root_task"), &BehaviorTree::get_root_task); ClassDB::bind_method(D_METHOD("clone"), &BehaviorTree::clone); @@ -55,4 +57,9 @@ void BehaviorTree::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "description", PROPERTY_HINT_MULTILINE_TEXT), "set_description", "get_description"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "root_task", PROPERTY_HINT_RESOURCE_TYPE, "BTTask", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_root_task", "get_root_task"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard_source", PROPERTY_HINT_RESOURCE_TYPE, "BlackboardSource", PROPERTY_USAGE_DEFAULT), "set_blackboard_source", "get_blackboard_source"); +} + +BehaviorTree::BehaviorTree() { + blackboard_source = Ref(memnew(BlackboardSource)); } diff --git a/bt/behavior_tree.h b/bt/behavior_tree.h index ffd6f53..3687524 100644 --- a/bt/behavior_tree.h +++ b/bt/behavior_tree.h @@ -12,11 +12,11 @@ #ifndef BEHAVIOR_TREE_H #define BEHAVIOR_TREE_H +#include "../blackboard/blackboard_source.h" #include "tasks/bt_task.h" #ifdef LIMBOAI_MODULE #include "core/io/resource.h" -#include "modules/limboai/blackboard/blackboard.h" #endif // LIMBOAI_MODULE #ifdef LIMBOAI_GDEXTENSION @@ -29,6 +29,7 @@ class BehaviorTree : public Resource { private: String description; + Ref blackboard_source; Ref root_task; protected: @@ -39,6 +40,12 @@ public: virtual bool editor_can_reload_from_file() override { return false; } #endif + void set_blackboard_source(const Ref &p_source) { + blackboard_source = p_source; + emit_changed(); + } + Ref get_blackboard_source() const { return blackboard_source; } + void set_description(String p_value) { description = p_value; emit_changed(); @@ -54,6 +61,8 @@ public: Ref clone() const; void copy_other(const Ref &p_other); Ref instantiate(Node *p_agent, const Ref &p_blackboard) const; + + BehaviorTree(); }; #endif // BEHAVIOR_TREE_H diff --git a/bt/bt_player.cpp b/bt/bt_player.cpp index b5e6d4e..9358791 100644 --- a/bt/bt_player.cpp +++ b/bt/bt_player.cpp @@ -63,11 +63,33 @@ void BTPlayer::_load_tree() { #endif } +void BTPlayer::_update_blackboard_source() { + if (behavior_tree.is_valid() && behavior_tree->get_blackboard_source().is_valid()) { + if (blackboard_source.is_null()) { + blackboard_source = Ref(memnew(BlackboardSource)); + } + if (blackboard_source == behavior_tree->get_blackboard_source()) { + blackboard_source->sync_base(); + } else { + blackboard_source->set_base_source(behavior_tree->get_blackboard_source()); + } + } +} + void BTPlayer::set_behavior_tree(const Ref &p_tree) { behavior_tree = p_tree; if (Engine::get_singleton()->is_editor_hint() == false && get_owner()) { _load_tree(); } + _update_blackboard_source(); +} + +void BTPlayer::set_blackboard_source(const Ref &p_source) { + blackboard_source = p_source; + if (blackboard_source.is_null()) { + blackboard_source = Ref(memnew(BlackboardSource)); + } + _update_blackboard_source(); } void BTPlayer::set_update_mode(UpdateMode p_mode) { diff --git a/bt/bt_player.h b/bt/bt_player.h index 70430d9..17238d8 100644 --- a/bt/bt_player.h +++ b/bt/bt_player.h @@ -47,6 +47,7 @@ private: Ref tree_instance; void _load_tree(); + void _update_blackboard_source(); protected: static void _bind_methods(); @@ -57,7 +58,7 @@ public: void set_behavior_tree(const Ref &p_tree); Ref get_behavior_tree() const { return behavior_tree; }; - void set_blackboard_source(const Ref &p_source) { blackboard_source = p_source; } + void set_blackboard_source(const Ref &p_source); Ref get_blackboard_source() const { return blackboard_source; } void set_update_mode(UpdateMode p_mode); diff --git a/bt/bt_state.cpp b/bt/bt_state.cpp index 2a18104..f71abb1 100644 --- a/bt/bt_state.cpp +++ b/bt/bt_state.cpp @@ -26,6 +26,19 @@ #include #endif // LIMBOAI_GDEXTENSION +void BTState::_update_blackboard_source() { + if (behavior_tree.is_valid() && behavior_tree->get_blackboard_source().is_valid()) { + if (get_blackboard_source().is_null()) { + set_blackboard_source(Ref(memnew(BlackboardSource))); + } + if (get_blackboard_source() == behavior_tree->get_blackboard_source()) { + get_blackboard_source()->sync_base(); + } else { + get_blackboard_source()->set_base_source(behavior_tree->get_blackboard_source()); + } + } +} + void BTState::_setup() { ERR_FAIL_COND_MSG(behavior_tree.is_null(), "BTState: BehaviorTree is not assigned."); tree_instance = behavior_tree->instantiate(get_agent(), get_blackboard()); diff --git a/bt/bt_state.h b/bt/bt_state.h index b3baa74..d492db2 100644 --- a/bt/bt_state.h +++ b/bt/bt_state.h @@ -26,6 +26,8 @@ private: String success_event; String failure_event; + void _update_blackboard_source(); + protected: static void _bind_methods(); diff --git a/register_types.cpp b/register_types.cpp index 4d6edf9..181c8b9 100644 --- a/register_types.cpp +++ b/register_types.cpp @@ -47,6 +47,7 @@ #include "blackboard/bb_param/bb_vector4.h" #include "blackboard/bb_param/bb_vector4i.h" #include "blackboard/blackboard.h" +#include "blackboard/blackboard_source.h" #include "bt/behavior_tree.h" #include "bt/bt_player.h" #include "bt/bt_state.h" @@ -133,6 +134,7 @@ void initialize_limboai_module(ModuleInitializationLevel p_level) { GDREGISTER_CLASS(LimboUtility); GDREGISTER_CLASS(Blackboard); + GDREGISTER_CLASS(BlackboardSource); GDREGISTER_CLASS(LimboState); GDREGISTER_CLASS(LimboHSM); diff --git a/util/limbo_compat.cpp b/util/limbo_compat.cpp index a02f34a..1e04f86 100644 --- a/util/limbo_compat.cpp +++ b/util/limbo_compat.cpp @@ -15,6 +15,7 @@ #ifdef TOOLS_ENABLED #include "core/io/resource.h" +#include "core/variant/variant.h" #include "editor/editor_node.h" #include "editor/plugins/script_editor_plugin.h" #endif // TOOLS_ENABLED @@ -85,6 +86,128 @@ Variant _GLOBAL_DEF(const PropertyInfo &p_info, const Variant &p_default, bool p // **** Shared +Variant VARIANT_DEFAULT(Variant::Type p_type) { + switch (p_type) { + case Variant::Type::NIL: { + return Variant(); + } break; + case Variant::Type::BOOL: { + return Variant(false); + } break; + case Variant::Type::INT: { + return Variant(0); + } break; + case Variant::Type::FLOAT: { + return Variant(0.0); + } break; + case Variant::Type::STRING: { + return Variant(""); + } break; + case Variant::Type::VECTOR2: { + return Variant(Vector2()); + } break; + case Variant::Type::VECTOR2I: { + return Variant(Vector2i()); + } break; + case Variant::Type::RECT2: { + return Variant(Rect2()); + } break; + case Variant::Type::RECT2I: { + return Variant(Rect2i()); + } break; + case Variant::Type::VECTOR3: { + return Variant(Vector3()); + } break; + case Variant::Type::VECTOR3I: { + return Variant(Vector3i()); + } break; + case Variant::Type::TRANSFORM2D: { + return Variant(Transform2D()); + } break; + case Variant::Type::VECTOR4: { + return Variant(Vector4()); + } break; + case Variant::Type::VECTOR4I: { + return Variant(Vector4i()); + } break; + case Variant::Type::PLANE: { + return Variant(Plane()); + } break; + case Variant::Type::QUATERNION: { + return Variant(Quaternion()); + } break; + case Variant::Type::AABB: { + return Variant(AABB()); + } break; + case Variant::Type::BASIS: { + return Variant(Basis()); + } break; + case Variant::Type::TRANSFORM3D: { + return Variant(Transform3D()); + } break; + case Variant::Type::PROJECTION: { + return Variant(Projection()); + } break; + case Variant::Type::COLOR: { + return Variant(Color()); + } break; + case Variant::Type::STRING_NAME: { + return Variant(StringName()); + } break; + case Variant::Type::NODE_PATH: { + return Variant(NodePath()); + } break; + case Variant::Type::RID: { + return Variant(RID()); + } break; + case Variant::Type::OBJECT: { + return Variant(); + } break; + case Variant::Type::CALLABLE: { + return Variant(); + } break; + case Variant::Type::SIGNAL: { + return Variant(); + } break; + case Variant::Type::DICTIONARY: { + return Variant(Dictionary()); + } break; + case Variant::Type::ARRAY: { + return Variant(Array()); + } break; + case Variant::Type::PACKED_BYTE_ARRAY: { + return Variant(PackedByteArray()); + } break; + case Variant::Type::PACKED_INT32_ARRAY: { + return Variant(PackedInt32Array()); + } break; + case Variant::Type::PACKED_INT64_ARRAY: { + return Variant(PackedInt64Array()); + } break; + case Variant::Type::PACKED_FLOAT32_ARRAY: { + return Variant(PackedFloat32Array()); + } break; + case Variant::Type::PACKED_FLOAT64_ARRAY: { + return Variant(PackedFloat64Array()); + } break; + case Variant::Type::PACKED_STRING_ARRAY: { + return Variant(PackedStringArray()); + } break; + case Variant::Type::PACKED_VECTOR2_ARRAY: { + return Variant(PackedVector2Array()); + } break; + case Variant::Type::PACKED_VECTOR3_ARRAY: { + return Variant(PackedVector3Array()); + } break; + case Variant::Type::PACKED_COLOR_ARRAY: { + return Variant(PackedColorArray()); + } break; + default: { + return Variant(); + } + } +} + #ifdef TOOLS_ENABLED void SHOW_DOC(const String &p_topic) { diff --git a/util/limbo_compat.h b/util/limbo_compat.h index a382f01..762aeaf 100644 --- a/util/limbo_compat.h +++ b/util/limbo_compat.h @@ -218,6 +218,8 @@ inline void VARIANT_DELETE_IF_OBJECT(Variant m_variant) { } } +Variant VARIANT_DEFAULT(Variant::Type p_type); + #define PROJECT_CONFIG_FILE() GET_PROJECT_SETTINGS_DIR().path_join("limbo_ai.cfg") #define IS_RESOURCE_FILE(m_path) (m_path.begins_with("res://") && m_path.find("::") == -1) #define RESOURCE_TYPE_HINT(m_type) vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, m_type)