Parsing BlackboardSource properties

This commit is contained in:
Serhii Snitsaruk 2024-01-23 15:31:56 +01:00
parent a247d0d67b
commit 8c67886b52
13 changed files with 296 additions and 5 deletions

View File

@ -11,6 +11,8 @@
#include "bb_variable.h" #include "bb_variable.h"
#include "../util/limbo_compat.h"
void BBVariable::unref() { void BBVariable::unref() {
if (data && data->refcount.unref()) { if (data && data->refcount.unref()) {
memdelete(data); memdelete(data);
@ -36,6 +38,7 @@ Variant BBVariable::get_value() const {
void BBVariable::set_type(Variant::Type p_type) { void BBVariable::set_type(Variant::Type p_type) {
data->type = p_type; data->type = p_type;
data->value = VARIANT_DEFAULT(p_type);
} }
Variant::Type BBVariable::get_type() const { 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 = memnew(Data);
data->refcount.init(); data->refcount.init();
set_type(p_type);
data->hint = p_hint;
data->hint_string = p_hint_string;
} }
BBVariable::~BBVariable() { BBVariable::~BBVariable() {

View File

@ -14,6 +14,7 @@
#include "core/object/object.h" #include "core/object/object.h"
#include "core/templates/safe_refcount.h" #include "core/templates/safe_refcount.h"
#include "core/variant/variant.h"
class BBVariable { class BBVariable {
private: private:
@ -60,7 +61,7 @@ public:
void operator=(const BBVariable &p_var); void operator=(const BBVariable &p_var);
BBVariable(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(); ~BBVariable();
}; };

View File

@ -11,6 +11,93 @@
#include "blackboard_source.h" #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<PropertyInfo> *p_list) const {
for (const KeyValue<String, BBVariable> &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<BlackboardSource> &p_base) {
base = p_base;
sync_base();
emit_changed();
}
void BlackboardSource::set_value(const String &p_name, const Variant &p_value) { void BlackboardSource::set_value(const String &p_name, const Variant &p_value) {
ERR_FAIL_COND(!data.has(p_name)); ERR_FAIL_COND(!data.has(p_name));
data.get(p_name).set_value(p_value); data.get(p_name).set_value(p_value);
@ -83,3 +170,10 @@ void BlackboardSource::populate_blackboard(const Ref<Blackboard> &p_blackboard,
p_blackboard->add_var(kv.key, kv.value.duplicate()); 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, ""));
}

View File

@ -25,7 +25,15 @@ private:
Ref<BlackboardSource> base; Ref<BlackboardSource> base;
// HashMap<String, BBVariable> overrides; // HashMap<String, BBVariable> 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<PropertyInfo> *p_list) const;
public: public:
void set_base_source(const Ref<BlackboardSource> &p_base);
Ref<BlackboardSource> get_base_source() const { return base; }
void set_value(const String &p_name, const Variant &p_value); void set_value(const String &p_name, const Variant &p_value);
Variant get_value(const String &p_name) const; Variant get_value(const String &p_name) const;
void add_var(const String &p_name, const BBVariable &p_var); void add_var(const String &p_name, const BBVariable &p_var);
@ -38,7 +46,7 @@ public:
Ref<Blackboard> create_blackboard(); Ref<Blackboard> create_blackboard();
void populate_blackboard(const Ref<Blackboard> &p_blackboard, bool overwrite); void populate_blackboard(const Ref<Blackboard> &p_blackboard, bool overwrite);
BlackboardSource() = default; BlackboardSource();
}; };
#endif // BLACKBOARD_SOURCE_H #endif // BLACKBOARD_SOURCE_H

View File

@ -47,6 +47,8 @@ Ref<BTTask> BehaviorTree::instantiate(Node *p_agent, const Ref<Blackboard> &p_bl
void BehaviorTree::_bind_methods() { void BehaviorTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_description", "p_value"), &BehaviorTree::set_description); 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("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("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("get_root_task"), &BehaviorTree::get_root_task);
ClassDB::bind_method(D_METHOD("clone"), &BehaviorTree::clone); 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::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, "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<BlackboardSource>(memnew(BlackboardSource));
} }

View File

@ -12,11 +12,11 @@
#ifndef BEHAVIOR_TREE_H #ifndef BEHAVIOR_TREE_H
#define BEHAVIOR_TREE_H #define BEHAVIOR_TREE_H
#include "../blackboard/blackboard_source.h"
#include "tasks/bt_task.h" #include "tasks/bt_task.h"
#ifdef LIMBOAI_MODULE #ifdef LIMBOAI_MODULE
#include "core/io/resource.h" #include "core/io/resource.h"
#include "modules/limboai/blackboard/blackboard.h"
#endif // LIMBOAI_MODULE #endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION #ifdef LIMBOAI_GDEXTENSION
@ -29,6 +29,7 @@ class BehaviorTree : public Resource {
private: private:
String description; String description;
Ref<BlackboardSource> blackboard_source;
Ref<BTTask> root_task; Ref<BTTask> root_task;
protected: protected:
@ -39,6 +40,12 @@ public:
virtual bool editor_can_reload_from_file() override { return false; } virtual bool editor_can_reload_from_file() override { return false; }
#endif #endif
void set_blackboard_source(const Ref<BlackboardSource> &p_source) {
blackboard_source = p_source;
emit_changed();
}
Ref<BlackboardSource> get_blackboard_source() const { return blackboard_source; }
void set_description(String p_value) { void set_description(String p_value) {
description = p_value; description = p_value;
emit_changed(); emit_changed();
@ -54,6 +61,8 @@ public:
Ref<BehaviorTree> clone() const; Ref<BehaviorTree> clone() const;
void copy_other(const Ref<BehaviorTree> &p_other); void copy_other(const Ref<BehaviorTree> &p_other);
Ref<BTTask> instantiate(Node *p_agent, const Ref<Blackboard> &p_blackboard) const; Ref<BTTask> instantiate(Node *p_agent, const Ref<Blackboard> &p_blackboard) const;
BehaviorTree();
}; };
#endif // BEHAVIOR_TREE_H #endif // BEHAVIOR_TREE_H

View File

@ -63,11 +63,33 @@ void BTPlayer::_load_tree() {
#endif #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<BlackboardSource>(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<BehaviorTree> &p_tree) { void BTPlayer::set_behavior_tree(const Ref<BehaviorTree> &p_tree) {
behavior_tree = p_tree; behavior_tree = p_tree;
if (Engine::get_singleton()->is_editor_hint() == false && get_owner()) { if (Engine::get_singleton()->is_editor_hint() == false && get_owner()) {
_load_tree(); _load_tree();
} }
_update_blackboard_source();
}
void BTPlayer::set_blackboard_source(const Ref<BlackboardSource> &p_source) {
blackboard_source = p_source;
if (blackboard_source.is_null()) {
blackboard_source = Ref<BlackboardSource>(memnew(BlackboardSource));
}
_update_blackboard_source();
} }
void BTPlayer::set_update_mode(UpdateMode p_mode) { void BTPlayer::set_update_mode(UpdateMode p_mode) {

View File

@ -47,6 +47,7 @@ private:
Ref<BTTask> tree_instance; Ref<BTTask> tree_instance;
void _load_tree(); void _load_tree();
void _update_blackboard_source();
protected: protected:
static void _bind_methods(); static void _bind_methods();
@ -57,7 +58,7 @@ public:
void set_behavior_tree(const Ref<BehaviorTree> &p_tree); void set_behavior_tree(const Ref<BehaviorTree> &p_tree);
Ref<BehaviorTree> get_behavior_tree() const { return behavior_tree; }; Ref<BehaviorTree> get_behavior_tree() const { return behavior_tree; };
void set_blackboard_source(const Ref<BlackboardSource> &p_source) { blackboard_source = p_source; } void set_blackboard_source(const Ref<BlackboardSource> &p_source);
Ref<BlackboardSource> get_blackboard_source() const { return blackboard_source; } Ref<BlackboardSource> get_blackboard_source() const { return blackboard_source; }
void set_update_mode(UpdateMode p_mode); void set_update_mode(UpdateMode p_mode);

View File

@ -26,6 +26,19 @@
#include <godot_cpp/classes/engine_debugger.hpp> #include <godot_cpp/classes/engine_debugger.hpp>
#endif // LIMBOAI_GDEXTENSION #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<BlackboardSource>(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() { void BTState::_setup() {
ERR_FAIL_COND_MSG(behavior_tree.is_null(), "BTState: BehaviorTree is not assigned."); ERR_FAIL_COND_MSG(behavior_tree.is_null(), "BTState: BehaviorTree is not assigned.");
tree_instance = behavior_tree->instantiate(get_agent(), get_blackboard()); tree_instance = behavior_tree->instantiate(get_agent(), get_blackboard());

View File

@ -26,6 +26,8 @@ private:
String success_event; String success_event;
String failure_event; String failure_event;
void _update_blackboard_source();
protected: protected:
static void _bind_methods(); static void _bind_methods();

View File

@ -47,6 +47,7 @@
#include "blackboard/bb_param/bb_vector4.h" #include "blackboard/bb_param/bb_vector4.h"
#include "blackboard/bb_param/bb_vector4i.h" #include "blackboard/bb_param/bb_vector4i.h"
#include "blackboard/blackboard.h" #include "blackboard/blackboard.h"
#include "blackboard/blackboard_source.h"
#include "bt/behavior_tree.h" #include "bt/behavior_tree.h"
#include "bt/bt_player.h" #include "bt/bt_player.h"
#include "bt/bt_state.h" #include "bt/bt_state.h"
@ -133,6 +134,7 @@ void initialize_limboai_module(ModuleInitializationLevel p_level) {
GDREGISTER_CLASS(LimboUtility); GDREGISTER_CLASS(LimboUtility);
GDREGISTER_CLASS(Blackboard); GDREGISTER_CLASS(Blackboard);
GDREGISTER_CLASS(BlackboardSource);
GDREGISTER_CLASS(LimboState); GDREGISTER_CLASS(LimboState);
GDREGISTER_CLASS(LimboHSM); GDREGISTER_CLASS(LimboHSM);

View File

@ -15,6 +15,7 @@
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
#include "core/io/resource.h" #include "core/io/resource.h"
#include "core/variant/variant.h"
#include "editor/editor_node.h" #include "editor/editor_node.h"
#include "editor/plugins/script_editor_plugin.h" #include "editor/plugins/script_editor_plugin.h"
#endif // TOOLS_ENABLED #endif // TOOLS_ENABLED
@ -85,6 +86,128 @@ Variant _GLOBAL_DEF(const PropertyInfo &p_info, const Variant &p_default, bool p
// **** Shared // **** 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 #ifdef TOOLS_ENABLED
void SHOW_DOC(const String &p_topic) { void SHOW_DOC(const String &p_topic) {

View File

@ -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 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 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) #define RESOURCE_TYPE_HINT(m_type) vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, m_type)