diff --git a/blackboard/blackboard.cpp b/blackboard/blackboard.cpp index cfd6973..d0769b7 100644 --- a/blackboard/blackboard.cpp +++ b/blackboard/blackboard.cpp @@ -34,51 +34,61 @@ Ref Blackboard::top() const { return bb; } -Variant Blackboard::get_var(const Variant &p_key, const Variant &p_default) const { - if (data.has(p_key)) { - return data.get(p_key, Variant()); +Variant Blackboard::get_var(const String &p_name, const Variant &p_default) const { + if (data.has(p_name)) { + return data.get(p_name).get_value(); } else if (parent.is_valid()) { - return parent->get_var(p_key, p_default); + return parent->get_var(p_name, p_default); } else { return p_default; } } -void Blackboard::set_var(const Variant &p_key, const Variant &p_value) { - data[p_key] = p_value; +void Blackboard::set_var(const String &p_name, const Variant &p_value) { + // TODO: Check if p_value can be converted into required type! + if (data.has(p_name)) { + data[p_name].set_value(p_value); + } else { + BBVariable var; + var.set_value(p_value); + data.insert(p_name, var); + } } -bool Blackboard::has_var(const Variant &p_key) const { - return data.has(p_key) || (parent.is_valid() && parent->has_var(p_key)); +bool Blackboard::has_var(const String &p_name) const { + return data.has(p_name) || (parent.is_valid() && parent->has_var(p_name)); } -void Blackboard::erase_var(const Variant &p_key) { - data.erase(p_key); +void Blackboard::erase_var(const String &p_name) { + data.erase(p_name); +} + +void Blackboard::add_var(const String &p_name, const BBVariable &p_var) { + ERR_FAIL_COND(data.has(p_name)); + data.insert(p_name, p_var); } void Blackboard::prefetch_nodepath_vars(Node *p_node) { ERR_FAIL_COND(p_node == nullptr); - Array keys = data.keys(); - Array values = data.values(); - for (int i = 0; i < keys.size(); i++) { - if (values[i].get_type() == Variant::NODE_PATH) { - Node *fetched_node = p_node->get_node_or_null(values[i]); + for (KeyValue &kv : data) { + if (kv.value.get_value().get_type() == Variant::NODE_PATH) { + Node *fetched_node = p_node->get_node_or_null(kv.value.get_value()); if (fetched_node != nullptr) { - data[keys[i]] = fetched_node; + kv.value.set_value(fetched_node); } } } } void Blackboard::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_data"), &Blackboard::get_data); - ClassDB::bind_method(D_METHOD("set_data", "p_data"), &Blackboard::set_data); - ClassDB::bind_method(D_METHOD("get_var", "p_key", "p_default"), &Blackboard::get_var, Variant()); - ClassDB::bind_method(D_METHOD("set_var", "p_key", "p_value"), &Blackboard::set_var); - ClassDB::bind_method(D_METHOD("has_var", "p_key"), &Blackboard::has_var); + ClassDB::bind_method(D_METHOD("get_var", "p_name", "p_default"), &Blackboard::get_var, Variant()); + ClassDB::bind_method(D_METHOD("set_var", "p_name", "p_value"), &Blackboard::set_var); + ClassDB::bind_method(D_METHOD("has_var", "p_name"), &Blackboard::has_var); ClassDB::bind_method(D_METHOD("set_parent_scope", "p_blackboard"), &Blackboard::set_parent_scope); ClassDB::bind_method(D_METHOD("get_parent_scope"), &Blackboard::get_parent_scope); - ClassDB::bind_method(D_METHOD("erase_var", "p_key"), &Blackboard::erase_var); + ClassDB::bind_method(D_METHOD("erase_var", "p_name"), &Blackboard::erase_var); ClassDB::bind_method(D_METHOD("prefetch_nodepath_vars", "p_node"), &Blackboard::prefetch_nodepath_vars); ClassDB::bind_method(D_METHOD("top"), &Blackboard::top); + // ClassDB::bind_method(D_METHOD("get_data"), &Blackboard::get_data); + // ClassDB::bind_method(D_METHOD("set_data", "p_data"), &Blackboard::set_data); } diff --git a/blackboard/blackboard.h b/blackboard/blackboard.h index 893bd89..062d8b2 100644 --- a/blackboard/blackboard.h +++ b/blackboard/blackboard.h @@ -12,6 +12,8 @@ #ifndef BLACKBOARD_H #define BLACKBOARD_H +#include "bb_variable.h" + #ifdef LIMBOAI_MODULE #include "core/object/object.h" #include "core/object/ref_counted.h" @@ -33,27 +35,30 @@ class Blackboard : public RefCounted { GDCLASS(Blackboard, RefCounted); private: - Dictionary data; + HashMap data; Ref parent; protected: static void _bind_methods(); public: - void set_data(const Dictionary &p_value) { data = p_value; } - Dictionary get_data() const { return data; } - void set_parent_scope(const Ref &p_blackboard) { parent = p_blackboard; } Ref get_parent_scope() const { return parent; } Ref top() const; - Variant get_var(const Variant &p_key, const Variant &p_default) const; - void set_var(const Variant &p_key, const Variant &p_value); - bool has_var(const Variant &p_key) const; - void erase_var(const Variant &p_key); + Variant get_var(const String &p_name, const Variant &p_default) const; + void set_var(const String &p_name, const Variant &p_value); + bool has_var(const String &p_name) const; + void erase_var(const String &p_name); + + void add_var(const String &p_name, const BBVariable &p_var); void prefetch_nodepath_vars(Node *p_node); + + // TODO: Rework serialization API. + // void set_data(const Dictionary &p_value); + // Dictionary get_data() const; }; -#endif // BLACKBOARD_H \ No newline at end of file +#endif // BLACKBOARD_H diff --git a/blackboard/blackboard_source.cpp b/blackboard/blackboard_source.cpp index 9b26fef..08cfb96 100644 --- a/blackboard/blackboard_source.cpp +++ b/blackboard/blackboard_source.cpp @@ -12,48 +12,48 @@ #include "blackboard_source.h" void BlackboardSource::set_value(const String &p_name, const Variant &p_value) { - ERR_FAIL_COND(!vars.has(p_name)); - vars.get(p_name).set_value(p_value); + ERR_FAIL_COND(!data.has(p_name)); + data.get(p_name).set_value(p_value); } Variant BlackboardSource::get_value(const String &p_name) const { - ERR_FAIL_COND_V(!vars.has(p_name), Variant()); - return vars.get(p_name).get_value(); + ERR_FAIL_COND_V(!data.has(p_name), Variant()); + return data.get(p_name).get_value(); } void BlackboardSource::add_var(const String &p_name, const BBVariable &p_var) { - ERR_FAIL_COND(vars.has(p_name)); + ERR_FAIL_COND(data.has(p_name)); ERR_FAIL_COND(base.is_valid()); - vars.insert(p_name, p_var); + data.insert(p_name, p_var); } void BlackboardSource::remove_var(const String &p_name) { - ERR_FAIL_COND(!vars.has(p_name)); + ERR_FAIL_COND(!data.has(p_name)); ERR_FAIL_COND(base.is_valid()); - vars.erase(p_name); + data.erase(p_name); } BBVariable BlackboardSource::get_var(const String &p_name) { - ERR_FAIL_COND_V(!vars.has(p_name), BBVariable()); - return vars.get(p_name); + ERR_FAIL_COND_V(!data.has(p_name), BBVariable()); + return data.get(p_name); } PackedStringArray BlackboardSource::list_vars() const { PackedStringArray ret; - for (const KeyValue &kv : vars) { + for (const KeyValue &kv : data) { ret.append(kv.key); } return ret; } void BlackboardSource::sync_base() { - for (const KeyValue &kv : base->vars) { - if (!vars.has(kv.key)) { - vars.insert(kv.key, kv.value.duplicate()); + for (const KeyValue &kv : base->data) { + if (!data.has(kv.key)) { + data.insert(kv.key, kv.value.duplicate()); continue; } - BBVariable var = vars.get(kv.key); + BBVariable var = data.get(kv.key); if (!var.is_same_prop_info(kv.value)) { var.copy_prop_info(kv.value); } @@ -63,8 +63,23 @@ void BlackboardSource::sync_base() { } } -Ref BlackboardSource::instantiate() { +Ref BlackboardSource::create_blackboard() { Ref bb = memnew(Blackboard); - // TODO: fill bb + for (const KeyValue &kv : data) { + bb->add_var(kv.key, kv.value.duplicate()); + } return bb; } + +void BlackboardSource::populate_blackboard(const Ref &p_blackboard, bool overwrite) { + for (const KeyValue &kv : data) { + if (p_blackboard->has_var(kv.key)) { + if (overwrite) { + p_blackboard->erase_var(kv.key); + } else { + continue; + } + } + p_blackboard->add_var(kv.key, kv.value.duplicate()); + } +} diff --git a/blackboard/blackboard_source.h b/blackboard/blackboard_source.h index 81dcdd5..38b4b5c 100644 --- a/blackboard/blackboard_source.h +++ b/blackboard/blackboard_source.h @@ -21,7 +21,7 @@ class BlackboardSource : public Resource { GDCLASS(BlackboardSource, Resource); private: - HashMap vars; + HashMap data; Ref base; // HashMap overrides; @@ -32,9 +32,11 @@ public: void remove_var(const String &p_name); BBVariable get_var(const String &p_name); PackedStringArray list_vars() const; + bool is_empty() const { return data.is_empty(); } void sync_base(); - Ref instantiate(); + Ref create_blackboard(); + void populate_blackboard(const Ref &p_blackboard, bool overwrite); BlackboardSource() = default; }; diff --git a/bt/bt_player.cpp b/bt/bt_player.cpp index 25d8004..b5e6d4e 100644 --- a/bt/bt_player.cpp +++ b/bt/bt_player.cpp @@ -160,6 +160,9 @@ void BTPlayer::_notification(int p_notification) { } break; case NOTIFICATION_READY: { if (!Engine::get_singleton()->is_editor_hint()) { + if (blackboard_source.is_valid()) { + blackboard = blackboard_source->create_blackboard(); + } if (behavior_tree.is_valid()) { _load_tree(); } @@ -196,8 +199,8 @@ void BTPlayer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_prefetch_nodepath_vars", "p_value"), &BTPlayer::set_prefetch_nodepath_vars); ClassDB::bind_method(D_METHOD("get_prefetch_nodepath_vars"), &BTPlayer::get_prefetch_nodepath_vars); - ClassDB::bind_method(D_METHOD("_set_blackboard_data", "p_blackboard"), &BTPlayer::_set_blackboard_data); - ClassDB::bind_method(D_METHOD("_get_blackboard_data"), &BTPlayer::_get_blackboard_data); + ClassDB::bind_method(D_METHOD("set_blackboard_source", "p_blackboard"), &BTPlayer::set_blackboard_source); + ClassDB::bind_method(D_METHOD("get_blackboard_source"), &BTPlayer::get_blackboard_source); ClassDB::bind_method(D_METHOD("update", "p_delta"), &BTPlayer::update); ClassDB::bind_method(D_METHOD("restart"), &BTPlayer::restart); @@ -207,7 +210,7 @@ void BTPlayer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "Idle,Physics,Manual"), "set_update_mode", "get_update_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "get_active"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard", PROPERTY_HINT_NONE, "Blackboard", 0), "set_blackboard", "get_blackboard"); - ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_blackboard_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_blackboard_data", "_get_blackboard_data"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard_source", PROPERTY_HINT_RESOURCE_TYPE, "BlackboardSource", PROPERTY_USAGE_DEFAULT), "set_blackboard_source", "get_blackboard_source"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "prefetch_nodepath_vars"), "set_prefetch_nodepath_vars", "get_prefetch_nodepath_vars"); BIND_ENUM_CONSTANT(IDLE); diff --git a/bt/bt_player.h b/bt/bt_player.h index 175fafc..70430d9 100644 --- a/bt/bt_player.h +++ b/bt/bt_player.h @@ -13,6 +13,7 @@ #define BT_PLAYER_H #include "../blackboard/blackboard.h" +#include "../blackboard/blackboard_source.h" #include "behavior_tree.h" #include "tasks/bt_task.h" @@ -36,6 +37,7 @@ public: private: Ref behavior_tree; + Ref blackboard_source; UpdateMode update_mode = UpdateMode::PHYSICS; bool active = true; Ref blackboard; @@ -49,15 +51,15 @@ private: protected: static void _bind_methods(); - void _set_blackboard_data(Dictionary p_value) { blackboard->set_data(p_value.duplicate()); } - Dictionary _get_blackboard_data() const { return blackboard->get_data(); } - void _notification(int p_notification); 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; } + Ref get_blackboard_source() const { return blackboard_source; } + void set_update_mode(UpdateMode p_mode); UpdateMode get_update_mode() const { return update_mode; } diff --git a/bt/tasks/decorators/bt_new_scope.cpp b/bt/tasks/decorators/bt_new_scope.cpp index 7bca1b3..faafd9f 100644 --- a/bt/tasks/decorators/bt_new_scope.cpp +++ b/bt/tasks/decorators/bt_new_scope.cpp @@ -15,9 +15,13 @@ void BTNewScope::initialize(Node *p_agent, const Ref &p_blackboard) ERR_FAIL_COND(p_agent == nullptr); ERR_FAIL_COND(p_blackboard == nullptr); - Ref bb = memnew(Blackboard); + Ref bb; + if (blackboard_source.is_valid()) { + bb = blackboard_source->create_blackboard(); + } else { + bb = Ref(memnew(Blackboard)); + } - bb->set_data(blackboard_data.duplicate()); bb->set_parent_scope(p_blackboard); BTDecorator::initialize(p_agent, bb); @@ -29,8 +33,8 @@ BT::Status BTNewScope::_tick(double p_delta) { } void BTNewScope::_bind_methods() { - ClassDB::bind_method(D_METHOD("_set_blackboard_data", "p_data"), &BTNewScope::_set_blackboard_data); - ClassDB::bind_method(D_METHOD("_get_blackboard_data"), &BTNewScope::_get_blackboard_data); + ClassDB::bind_method(D_METHOD("set_blackboard_source", "p_source"), &BTNewScope::set_blackboard_source); + ClassDB::bind_method(D_METHOD("get_blackboard_source"), &BTNewScope::get_blackboard_source); - ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_blackboard_data"), "_set_blackboard_data", "_get_blackboard_data"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard_source", PROPERTY_HINT_RESOURCE_TYPE, "BlackboardSource", PROPERTY_USAGE_DEFAULT), "set_blackboard_source", "get_blackboard_source"); } diff --git a/bt/tasks/decorators/bt_new_scope.h b/bt/tasks/decorators/bt_new_scope.h index 919ac89..8410990 100644 --- a/bt/tasks/decorators/bt_new_scope.h +++ b/bt/tasks/decorators/bt_new_scope.h @@ -14,18 +14,20 @@ #include "../bt_decorator.h" +#include "../../../blackboard/blackboard_source.h" + class BTNewScope : public BTDecorator { GDCLASS(BTNewScope, BTDecorator); TASK_CATEGORY(Decorators); private: - Dictionary blackboard_data; + Ref blackboard_source; protected: static void _bind_methods(); - void _set_blackboard_data(const Dictionary &p_value) { blackboard_data = p_value; } - Dictionary _get_blackboard_data() const { return blackboard_data; } + void set_blackboard_source(const Ref &p_source) { blackboard_source = p_source; } + Ref get_blackboard_source() const { return blackboard_source; } virtual Status _tick(double p_delta) override; diff --git a/hsm/limbo_state.cpp b/hsm/limbo_state.cpp index 4950e21..d751789 100644 --- a/hsm/limbo_state.cpp +++ b/hsm/limbo_state.cpp @@ -69,7 +69,8 @@ void LimboState::_initialize(Node *p_agent, const Ref &p_blackboard) agent = p_agent; if (!p_blackboard.is_null()) { - if (!blackboard->get_data().is_empty()) { + if (blackboard_source.is_valid() && !blackboard_source->is_empty()) { + blackboard = blackboard_source->create_blackboard(); blackboard->set_parent_scope(p_blackboard); } else { blackboard = p_blackboard; @@ -179,8 +180,8 @@ void LimboState::_bind_methods() { ClassDB::bind_method(D_METHOD("clear_guard"), &LimboState::clear_guard); ClassDB::bind_method(D_METHOD("get_blackboard"), &LimboState::get_blackboard); - ClassDB::bind_method(D_METHOD("_set_blackboard_data", "p_blackboard"), &LimboState::_set_blackboard_data); - ClassDB::bind_method(D_METHOD("_get_blackboard_data"), &LimboState::_get_blackboard_data); + ClassDB::bind_method(D_METHOD("set_blackboard_source", "p_source"), &LimboState::set_blackboard_source); + ClassDB::bind_method(D_METHOD("get_blackboard_source"), &LimboState::get_blackboard_source); #ifdef LIMBOAI_MODULE GDVIRTUAL_BIND(_setup); @@ -194,7 +195,7 @@ void LimboState::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "EVENT_FINISHED", PROPERTY_HINT_NONE, "", 0), "", "event_finished"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "agent", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_agent", "get_agent"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard", PROPERTY_HINT_RESOURCE_TYPE, "Blackboard", 0), "", "get_blackboard"); - ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_blackboard_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_blackboard_data", "_get_blackboard_data"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard_source", PROPERTY_HINT_RESOURCE_TYPE, "BlackboardSource", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_blackboard_source", "get_blackboard_source"); ADD_SIGNAL(MethodInfo("setup")); ADD_SIGNAL(MethodInfo("entered")); diff --git a/hsm/limbo_state.h b/hsm/limbo_state.h index 7a908d6..f9d84cd 100644 --- a/hsm/limbo_state.h +++ b/hsm/limbo_state.h @@ -13,6 +13,7 @@ #define LIMBO_STATE_H #include "../blackboard/blackboard.h" +#include "../blackboard/blackboard_source.h" #include "../util/limbo_string_names.h" @@ -37,6 +38,7 @@ class LimboState : public Node { GDCLASS(LimboState, Node); private: + Ref blackboard_source; Node *agent; Ref blackboard; HashMap handlers; @@ -51,9 +53,6 @@ protected: void _notification(int p_what); - void _set_blackboard_data(Dictionary p_value) { blackboard->set_data(p_value.duplicate()); } - Dictionary _get_blackboard_data() const { return blackboard->get_data(); } - virtual void _initialize(Node *p_agent, const Ref &p_blackboard); virtual void _setup(); @@ -71,6 +70,9 @@ protected: void add_event_handler(const String &p_event, const Callable &p_handler); public: + void set_blackboard_source(const Ref p_source) { blackboard_source = p_source; } + Ref get_blackboard_source() const { return blackboard_source; } + Ref get_blackboard() const { return blackboard; } Node *get_agent() const { return agent; }