Blackboard: Add variable-to-property binding interface
This commit is contained in:
parent
a6717ec76d
commit
c81c1ec872
|
@ -20,19 +20,35 @@ void BBVariable::unref() {
|
||||||
data = nullptr;
|
data = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// void BBVariable::init_ref() {
|
|
||||||
// if (data) {
|
|
||||||
// unref();
|
|
||||||
// }
|
|
||||||
// data = memnew(Data);
|
|
||||||
// data->refcount.init();
|
|
||||||
// }
|
|
||||||
|
|
||||||
void BBVariable::set_value(const Variant &p_value) {
|
void BBVariable::set_value(const Variant &p_value) {
|
||||||
data->value = p_value;
|
data->value = p_value; // Setting value even when bound as a fallback in case the binding fails.
|
||||||
|
|
||||||
|
if (is_bound()) {
|
||||||
|
Object *obj = ObjectDB::get_instance(ObjectID(data->bound_object));
|
||||||
|
ERR_FAIL_COND_MSG(!obj, "Blackboard: Failed to get bound object.");
|
||||||
|
#ifdef LIMBOAI_MODULE
|
||||||
|
bool r_valid;
|
||||||
|
obj->set(data->bound_property, p_value, &r_valid);
|
||||||
|
ERR_FAIL_COND_MSG(!r_valid, vformat("Blackboard: Failed to set bound property `%s` on %s", data->bound_property, obj));
|
||||||
|
#elif LIMBOAI_GDEXTENSION
|
||||||
|
obj->set(data->bound_property, p_value);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Variant BBVariable::get_value() const {
|
Variant BBVariable::get_value() const {
|
||||||
|
if (is_bound()) {
|
||||||
|
Object *obj = ObjectDB::get_instance(ObjectID(data->bound_object));
|
||||||
|
ERR_FAIL_COND_V_MSG(!obj, data->value, "Blackboard: Failed to get bound object.");
|
||||||
|
#ifdef LIMBOAI_MODULE
|
||||||
|
bool r_valid;
|
||||||
|
Variant ret = obj->get(data->bound_property, &r_valid);
|
||||||
|
ERR_FAIL_COND_V_MSG(!r_valid, data->value, vformat("Blackboard: Failed to get bound property `%s` on %s", data->bound_property, obj));
|
||||||
|
#elif LIMBOAI_GDEXTENSION
|
||||||
|
Variant ret = obj->get(data->bound_property);
|
||||||
|
#endif
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
return data->value;
|
return data->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,6 +105,19 @@ void BBVariable::copy_prop_info(const BBVariable &p_other) {
|
||||||
data->hint_string = p_other.data->hint_string;
|
data->hint_string = p_other.data->hint_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BBVariable::bind(Object *p_object, const StringName &p_property) {
|
||||||
|
ERR_FAIL_NULL_MSG(p_object, "Blackboard: Binding failed - object is null.");
|
||||||
|
ERR_FAIL_COND_MSG(p_property == StringName(), "Blackboard: Binding failed - property name is empty.");
|
||||||
|
ERR_FAIL_COND_MSG(!OBJECT_HAS_PROPERTY(p_object, p_property), vformat("Blackboard: Binding failed - %s has no property `%s`.", p_object, p_property));
|
||||||
|
data->bound_object = p_object->get_instance_id();
|
||||||
|
data->bound_property = p_property;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BBVariable::unbind() {
|
||||||
|
data->bound_object = 0;
|
||||||
|
data->bound_property = StringName();
|
||||||
|
}
|
||||||
|
|
||||||
bool BBVariable::operator==(const BBVariable &p_var) const {
|
bool BBVariable::operator==(const BBVariable &p_var) const {
|
||||||
if (data == p_var.data) {
|
if (data == p_var.data) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -14,14 +14,10 @@
|
||||||
|
|
||||||
#ifdef LIMBOAI_MODULE
|
#ifdef LIMBOAI_MODULE
|
||||||
#include "core/object/object.h"
|
#include "core/object/object.h"
|
||||||
#include "core/templates/safe_refcount.h"
|
|
||||||
#include "core/variant/variant.h"
|
|
||||||
#endif // LIMBOAI_MODULE
|
#endif // LIMBOAI_MODULE
|
||||||
|
|
||||||
#ifdef LIMBOAI_GDEXTENSION
|
#ifdef LIMBOAI_GDEXTENSION
|
||||||
#include "godot_cpp/core/defs.hpp"
|
#include "godot_cpp/core/object.hpp"
|
||||||
#include "godot_cpp/templates/safe_refcount.hpp"
|
|
||||||
#include "godot_cpp/variant/variant.hpp"
|
|
||||||
using namespace godot;
|
using namespace godot;
|
||||||
#endif // LIMBOAI_GDEXTENSION
|
#endif // LIMBOAI_GDEXTENSION
|
||||||
|
|
||||||
|
@ -33,14 +29,14 @@ private:
|
||||||
Variant::Type type = Variant::NIL;
|
Variant::Type type = Variant::NIL;
|
||||||
PropertyHint hint = PropertyHint::PROPERTY_HINT_NONE;
|
PropertyHint hint = PropertyHint::PROPERTY_HINT_NONE;
|
||||||
String hint_string;
|
String hint_string;
|
||||||
// bool bound = false;
|
|
||||||
// uint64_t bound_object = 0;
|
NodePath binding_path;
|
||||||
// StringName bound_property;
|
uint64_t bound_object = 0;
|
||||||
|
StringName bound_property;
|
||||||
};
|
};
|
||||||
|
|
||||||
Data *data = nullptr;
|
Data *data = nullptr;
|
||||||
void unref();
|
void unref();
|
||||||
// void init_ref();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void set_value(const Variant &p_value);
|
void set_value(const Variant &p_value);
|
||||||
|
@ -60,10 +56,15 @@ public:
|
||||||
bool is_same_prop_info(const BBVariable &p_other) const;
|
bool is_same_prop_info(const BBVariable &p_other) const;
|
||||||
void copy_prop_info(const BBVariable &p_other);
|
void copy_prop_info(const BBVariable &p_other);
|
||||||
|
|
||||||
// bool is_bound() { return bound; }
|
// * Editor binding methods
|
||||||
|
String get_binding_path() const { return data->binding_path; }
|
||||||
|
void set_binding_path(const String &p_binding_path) { data->binding_path = p_binding_path; }
|
||||||
|
bool has_binding() { return data->binding_path.is_empty(); }
|
||||||
|
|
||||||
// void bind(Node *p_root, NodePath p_path);
|
// * Runtime binding methods
|
||||||
// void unbind();
|
bool is_bound() const { return data->bound_object != 0; }
|
||||||
|
void bind(Object *p_object, const StringName &p_property);
|
||||||
|
void unbind();
|
||||||
|
|
||||||
bool operator==(const BBVariable &p_var) const;
|
bool operator==(const BBVariable &p_var) const;
|
||||||
bool operator!=(const BBVariable &p_var) const;
|
bool operator!=(const BBVariable &p_var) const;
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
#include "blackboard.h"
|
#include "blackboard.h"
|
||||||
|
|
||||||
#ifdef LIMBOAI_MODULE
|
#ifdef LIMBOAI_MODULE
|
||||||
#include "core/error/error_macros.h"
|
|
||||||
#include "core/variant/variant.h"
|
#include "core/variant/variant.h"
|
||||||
#include "scene/main/node.h"
|
#include "scene/main/node.h"
|
||||||
#endif // LIMBOAI_MODULE
|
#endif // LIMBOAI_MODULE
|
||||||
|
@ -62,6 +61,16 @@ void Blackboard::erase_var(const String &p_name) {
|
||||||
data.erase(p_name);
|
data.erase(p_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Blackboard::bind_var_to_property(const String &p_name, Object *p_object, const StringName &p_property) {
|
||||||
|
ERR_FAIL_COND_MSG(!data.has(p_name), "Blackboard: Binding failed - can't bind variable that doesn't exist.");
|
||||||
|
data[p_name].bind(p_object, p_property);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Blackboard::unbind_var(const String &p_name) {
|
||||||
|
ERR_FAIL_COND_MSG(data.has(p_name), "Blackboard: Can't unbind variable that doesn't exist.");
|
||||||
|
data[p_name].unbind();
|
||||||
|
}
|
||||||
|
|
||||||
void Blackboard::add_var(const String &p_name, const BBVariable &p_var) {
|
void Blackboard::add_var(const String &p_name, const BBVariable &p_var) {
|
||||||
ERR_FAIL_COND(data.has(p_name));
|
ERR_FAIL_COND(data.has(p_name));
|
||||||
data.insert(p_name, p_var);
|
data.insert(p_name, p_var);
|
||||||
|
@ -89,4 +98,6 @@ void Blackboard::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("erase_var", "p_name"), &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("prefetch_nodepath_vars", "p_node"), &Blackboard::prefetch_nodepath_vars);
|
||||||
ClassDB::bind_method(D_METHOD("top"), &Blackboard::top);
|
ClassDB::bind_method(D_METHOD("top"), &Blackboard::top);
|
||||||
|
ClassDB::bind_method(D_METHOD("bind_var_to_property", "p_name", "p_object", "p_property"), &Blackboard::bind_var_to_property);
|
||||||
|
ClassDB::bind_method(D_METHOD("unbind_var", "p_name"), &Blackboard::unbind_var);
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,9 @@ public:
|
||||||
bool has_var(const String &p_name) const;
|
bool has_var(const String &p_name) const;
|
||||||
void erase_var(const String &p_name);
|
void erase_var(const String &p_name);
|
||||||
|
|
||||||
|
void bind_var_to_property(const String &p_name, Object *p_object, const StringName &p_property);
|
||||||
|
void unbind_var(const String &p_name);
|
||||||
|
|
||||||
void add_var(const String &p_name, const BBVariable &p_var);
|
void add_var(const String &p_name, const BBVariable &p_var);
|
||||||
|
|
||||||
void prefetch_nodepath_vars(Node *p_node);
|
void prefetch_nodepath_vars(Node *p_node);
|
||||||
|
|
|
@ -11,6 +11,15 @@
|
||||||
<tutorials>
|
<tutorials>
|
||||||
</tutorials>
|
</tutorials>
|
||||||
<methods>
|
<methods>
|
||||||
|
<method name="bind_var_to_property">
|
||||||
|
<return type="void" />
|
||||||
|
<param index="0" name="p_name" type="String" />
|
||||||
|
<param index="1" name="p_object" type="Object" />
|
||||||
|
<param index="2" name="p_property" type="StringName" />
|
||||||
|
<description>
|
||||||
|
Establish a binding between a variable and the object's property specified by [param p_property] and [param p_object]. Changes to the variable update the property, and vice versa.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="erase_var">
|
<method name="erase_var">
|
||||||
<return type="void" />
|
<return type="void" />
|
||||||
<param index="0" name="p_name" type="String" />
|
<param index="0" name="p_name" type="String" />
|
||||||
|
@ -67,5 +76,12 @@
|
||||||
Returns the topmost [Blackboard] in the scope chain.
|
Returns the topmost [Blackboard] in the scope chain.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="unbind_var">
|
||||||
|
<return type="void" />
|
||||||
|
<param index="0" name="p_name" type="String" />
|
||||||
|
<description>
|
||||||
|
Remove binding from a variable.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
</methods>
|
</methods>
|
||||||
</class>
|
</class>
|
||||||
|
|
|
@ -54,6 +54,11 @@
|
||||||
#define GET_SCRIPT(m_obj) (m_obj->get_script_instance() ? m_obj->get_script_instance()->get_script() : nullptr)
|
#define GET_SCRIPT(m_obj) (m_obj->get_script_instance() ? m_obj->get_script_instance()->get_script() : nullptr)
|
||||||
#define ADD_STYLEBOX_OVERRIDE(m_control, m_name, m_stylebox) (m_control->add_theme_style_override(m_name, m_stylebox))
|
#define ADD_STYLEBOX_OVERRIDE(m_control, m_name, m_stylebox) (m_control->add_theme_style_override(m_name, m_stylebox))
|
||||||
|
|
||||||
|
_FORCE_INLINE_ bool OBJECT_HAS_PROPERTY(Object *p_obj, const StringName &p_prop) {
|
||||||
|
bool r_valid;
|
||||||
|
return Variant(p_obj).has_key(p_prop, r_valid);
|
||||||
|
}
|
||||||
|
|
||||||
#define VARIANT_EVALUATE(m_op, m_lvalue, m_rvalue, r_ret) r_ret = Variant::evaluate(m_op, m_lvalue, m_rvalue)
|
#define VARIANT_EVALUATE(m_op, m_lvalue, m_rvalue, r_ret) r_ret = Variant::evaluate(m_op, m_lvalue, m_rvalue)
|
||||||
|
|
||||||
// * Virtual calls
|
// * Virtual calls
|
||||||
|
@ -133,6 +138,10 @@ using namespace godot;
|
||||||
#define GET_SCRIPT(m_obj) (m_obj->get_script())
|
#define GET_SCRIPT(m_obj) (m_obj->get_script())
|
||||||
#define ADD_STYLEBOX_OVERRIDE(m_control, m_name, m_stylebox) (m_control->add_theme_stylebox_override(m_name, m_stylebox))
|
#define ADD_STYLEBOX_OVERRIDE(m_control, m_name, m_stylebox) (m_control->add_theme_stylebox_override(m_name, m_stylebox))
|
||||||
|
|
||||||
|
_FORCE_INLINE_ bool OBJECT_HAS_PROPERTY(Object *p_obj, const StringName &p_prop) {
|
||||||
|
return Variant(p_obj).has_key(p_prop);
|
||||||
|
}
|
||||||
|
|
||||||
#define VARIANT_EVALUATE(m_op, m_lvalue, m_rvalue, r_ret) \
|
#define VARIANT_EVALUATE(m_op, m_lvalue, m_rvalue, r_ret) \
|
||||||
{ \
|
{ \
|
||||||
bool r_valid; \
|
bool r_valid; \
|
||||||
|
|
Loading…
Reference in New Issue