Store property bindings in BlackboardPlan

This commit is contained in:
Serhii Snitsaruk 2024-11-10 19:08:56 +01:00
parent ae61d551c0
commit f600d633a3
No known key found for this signature in database
GPG Key ID: A965EF8799FFEC2D
2 changed files with 64 additions and 12 deletions

View File

@ -31,24 +31,45 @@ bool BlackboardPlan::_set(const StringName &p_name, const Variant &p_value) {
if (name_str.begins_with("mapping/")) { if (name_str.begins_with("mapping/")) {
StringName mapped_var_name = name_str.get_slicec('/', 1); StringName mapped_var_name = name_str.get_slicec('/', 1);
StringName value = p_value; StringName value = p_value;
bool properties_changed = false; bool prop_list_changed = false;
if (value == StringName()) { if (value == StringName()) {
if (parent_scope_mapping.has(mapped_var_name)) { if (parent_scope_mapping.has(mapped_var_name)) {
properties_changed = true; prop_list_changed = true;
parent_scope_mapping.erase(mapped_var_name); parent_scope_mapping.erase(mapped_var_name);
} }
} else { } else {
if (!parent_scope_mapping.has(mapped_var_name)) { if (!parent_scope_mapping.has(mapped_var_name)) {
properties_changed = true; prop_list_changed = true;
} }
parent_scope_mapping[mapped_var_name] = value; parent_scope_mapping[mapped_var_name] = value;
} }
if (properties_changed) { if (prop_list_changed) {
notify_property_list_changed(); notify_property_list_changed();
} }
return true; return true;
} }
// * Binding
if (name_str.begins_with("binding/")) {
StringName bound_var = name_str.get_slicec('/', 1);
NodePath value = p_value;
bool prop_list_changed = false;
if (value.is_empty()) {
if (property_bindings.has(bound_var)) {
prop_list_changed = true;
property_bindings.erase(bound_var);
}
} else {
if (!property_bindings.has(bound_var)) {
prop_list_changed = true;
}
property_bindings[bound_var] = value;
}
if (prop_list_changed) {
notify_property_list_changed();
}
}
// * Storage // * Storage
if (name_str.begins_with("var/")) { if (name_str.begins_with("var/")) {
StringName var_name = name_str.get_slicec('/', 1); StringName var_name = name_str.get_slicec('/', 1);
@ -66,6 +87,8 @@ bool BlackboardPlan::_set(const StringName &p_name, const Variant &p_value) {
var_map[var_name].set_hint((PropertyHint)(int)p_value); var_map[var_name].set_hint((PropertyHint)(int)p_value);
} else if (what == "hint_string") { } else if (what == "hint_string") {
var_map[var_name].set_hint_string(p_value); var_map[var_name].set_hint_string(p_value);
} else if (what == "property_binding") {
property_bindings[var_name] = NodePath(p_value);
} else { } else {
return false; return false;
} }
@ -82,6 +105,8 @@ bool BlackboardPlan::_get(const StringName &p_name, Variant &r_ret) const {
if (var_map.has(p_name)) { if (var_map.has(p_name)) {
if (has_mapping(p_name)) { if (has_mapping(p_name)) {
r_ret = "Mapped to " + LimboUtility::get_singleton()->decorate_var(parent_scope_mapping[p_name]); r_ret = "Mapped to " + LimboUtility::get_singleton()->decorate_var(parent_scope_mapping[p_name]);
} else if (has_property_binding(p_name)) {
r_ret = "Bound to " + property_bindings[p_name];
} else { } else {
r_ret = var_map[p_name].get_value(); r_ret = var_map[p_name].get_value();
} }
@ -92,11 +117,15 @@ bool BlackboardPlan::_get(const StringName &p_name, Variant &r_ret) const {
if (name_str.begins_with("mapping/")) { if (name_str.begins_with("mapping/")) {
StringName mapped_var_name = name_str.get_slicec('/', 1); StringName mapped_var_name = name_str.get_slicec('/', 1);
ERR_FAIL_COND_V(mapped_var_name == StringName(), false); ERR_FAIL_COND_V(mapped_var_name == StringName(), false);
if (parent_scope_mapping.has(mapped_var_name)) { r_ret = parent_scope_mapping.has(mapped_var_name) ? parent_scope_mapping[mapped_var_name] : StringName();
r_ret = parent_scope_mapping[mapped_var_name]; return true;
} else { }
r_ret = StringName();
} // * Binding
if (name_str.begins_with("binding/")) {
StringName bound_var = name_str.get_slicec('/', 1);
ERR_FAIL_COND_V(bound_var == StringName(), false);
r_ret = property_bindings.has(bound_var) ? property_bindings[bound_var] : NodePath();
return true; return true;
} }
@ -129,7 +158,7 @@ void BlackboardPlan::_get_property_list(List<PropertyInfo> *p_list) const {
// * Editor // * Editor
if (var.get_type() != Variant::NIL && (!is_derived() || !var_name.begins_with("_"))) { if (var.get_type() != Variant::NIL && (!is_derived() || !var_name.begins_with("_"))) {
if (has_mapping(var_name)) { if (has_mapping(var_name) || has_property_binding(var_name)) {
p_list->push_back(PropertyInfo(Variant::STRING, var_name, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_READ_ONLY)); p_list->push_back(PropertyInfo(Variant::STRING, var_name, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_READ_ONLY));
} else { } else {
p_list->push_back(PropertyInfo(var.get_type(), var_name, var.get_hint(), var.get_hint_string(), PROPERTY_USAGE_EDITOR)); p_list->push_back(PropertyInfo(var.get_type(), var_name, var.get_hint(), var.get_hint_string(), PROPERTY_USAGE_EDITOR));
@ -158,6 +187,15 @@ void BlackboardPlan::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::STRING_NAME, "mapping/" + p.first, PROPERTY_HINT_NONE, "", usage)); p_list->push_back(PropertyInfo(Variant::STRING_NAME, "mapping/" + p.first, PROPERTY_HINT_NONE, "", usage));
} }
} }
// * Binding
p_list->push_back(PropertyInfo(Variant::NIL, "Binding", PROPERTY_HINT_NONE, "binding/", PROPERTY_USAGE_GROUP));
for (const Pair<StringName, BBVariable> &p : var_list) {
PropertyUsageFlags usage = has_property_binding(p.first) ? PROPERTY_USAGE_DEFAULT : PROPERTY_USAGE_EDITOR;
// PROPERTY_HINT_LINK is used to signal that NodePath should point to a property.
// Our inspector plugin will know how to handle it.
p_list->push_back(PropertyInfo(Variant::NODE_PATH, "binding/" + p.first, PROPERTY_HINT_LINK, "", usage));
}
} }
bool BlackboardPlan::_property_can_revert(const StringName &p_name) const { bool BlackboardPlan::_property_can_revert(const StringName &p_name) const {
@ -199,6 +237,11 @@ bool BlackboardPlan::has_mapping(const StringName &p_name) const {
return is_mapping_enabled() && parent_scope_mapping.has(p_name) && parent_scope_mapping[p_name] != StringName(); return is_mapping_enabled() && parent_scope_mapping.has(p_name) && parent_scope_mapping[p_name] != StringName();
} }
void BlackboardPlan::set_property_binding(const StringName &p_name, const NodePath &p_path) {
property_bindings[p_name] = p_path;
emit_changed();
}
void BlackboardPlan::set_prefetch_nodepath_vars(bool p_enable) { void BlackboardPlan::set_prefetch_nodepath_vars(bool p_enable) {
prefetch_nodepath_vars = p_enable; prefetch_nodepath_vars = p_enable;
emit_changed(); emit_changed();

View File

@ -34,15 +34,20 @@ private:
// When base is not null, the plan is considered to be derived from the base plan. // When base is not null, the plan is considered to be derived from the base plan.
// A derived plan can only have variables that exist in the base plan, // A derived plan can only have variables that exist in the base plan,
// and only the values can be different in those variables. // and only the values can be different in those variables.
// The derived plan is synced with the base plan to maintain consistency.
Ref<BlackboardPlan> base; Ref<BlackboardPlan> base;
// Mapping between variables in this plan and their parent scope names. // Mapping between variables in this plan and their parent scope names.
// Used for linking variables to their parent scope counterparts upon Blackboard creation/population. // Used for linking variables to their parent scope counterparts upon Blackboard creation/population.
HashMap<StringName, StringName> parent_scope_mapping; HashMap<StringName, StringName> parent_scope_mapping;
// Fetcher function for the parent scope plan. Funtion should return a Ref<BlackboardPlan>. // Fetcher function for the parent scope plan. Function should return a Ref<BlackboardPlan>.
// Used in the inspector. When set, mapping feature becomes available. // Used in the inspector: enables mapping feature when set.
Callable parent_scope_plan_provider; Callable parent_scope_plan_provider;
// Bindings to properties in the scene to which this plan belongs.
HashMap<StringName, NodePath> property_bindings;
bool property_binding_enabled = false;
// If true, NodePath variables will be prefetched, so that the vars will contain node pointers instead (upon BB creation/population). // If true, NodePath variables will be prefetched, so that the vars will contain node pointers instead (upon BB creation/population).
bool prefetch_nodepath_vars = true; bool prefetch_nodepath_vars = true;
@ -69,6 +74,10 @@ public:
bool is_mapping_enabled() const { return parent_scope_plan_provider.is_valid() && (parent_scope_plan_provider.call() != Ref<BlackboardPlan>()); } bool is_mapping_enabled() const { return parent_scope_plan_provider.is_valid() && (parent_scope_plan_provider.call() != Ref<BlackboardPlan>()); }
bool has_mapping(const StringName &p_name) const; bool has_mapping(const StringName &p_name) const;
bool has_property_binding(const StringName &p_name) const { return property_bindings.has(p_name); }
void set_property_binding(const StringName &p_name, const NodePath &p_path);
NodePath get_property_binding(const StringName &p_name) const { return property_bindings.has(p_name) ? property_bindings[p_name] : NodePath(); }
void set_prefetch_nodepath_vars(bool p_enable); void set_prefetch_nodepath_vars(bool p_enable);
bool is_prefetching_nodepath_vars() const; bool is_prefetching_nodepath_vars() const;