Merge pull request #20 from limbonaut/blackboard-improvements
Rework `Blackboard` API and introduce `BlackboardPlan` resource and editor. - `BBVariable` object holds the value of a blackboard variable and its metadata (not exposed to the API). - `BlackboardPlan` resource stores and manages a collection of variables, and is used to construct new `Blackboard` instances. - Each `BehaviorTree` resource has its own `BlackboardPlan` resource that acts as a blueprint. - `BTPlayer` also has its own `BlackboardPlan` which extends the behavior tree `BlackboardPlan` resource, i.e. variables from BehaviorTree are overridden in the BTPlayer node. - Editor for the `BlackboardPlan` resources - Accessed with "Manage" button in the inspector. - Rename, reposition, and change type and hint of the blackboard variables. - Edit default variable values directly in the inspector. - Define variables in the `BehaviorTree` blackboard plan and override those variables in the `BTPlayer`'s plan. - Fully compatible with both module and GDExtension builds!
This commit is contained in:
commit
662738e6bf
|
@ -0,0 +1,153 @@
|
|||
/**
|
||||
* bb_variable.cpp
|
||||
* =============================================================================
|
||||
* Copyright 2021-2024 Serhii Snitsaruk
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#include "bb_variable.h"
|
||||
|
||||
#include "../util/limbo_compat.h"
|
||||
|
||||
void BBVariable::unref() {
|
||||
if (data && data->refcount.unref()) {
|
||||
memdelete(data);
|
||||
}
|
||||
data = nullptr;
|
||||
}
|
||||
|
||||
// void BBVariable::init_ref() {
|
||||
// if (data) {
|
||||
// unref();
|
||||
// }
|
||||
// data = memnew(Data);
|
||||
// data->refcount.init();
|
||||
// }
|
||||
|
||||
void BBVariable::set_value(const Variant &p_value) {
|
||||
data->value = p_value;
|
||||
}
|
||||
|
||||
Variant BBVariable::get_value() const {
|
||||
return data->value;
|
||||
}
|
||||
|
||||
void BBVariable::set_type(Variant::Type p_type) {
|
||||
data->type = p_type;
|
||||
data->value = VARIANT_DEFAULT(p_type);
|
||||
}
|
||||
|
||||
Variant::Type BBVariable::get_type() const {
|
||||
return data->type;
|
||||
}
|
||||
|
||||
void BBVariable::set_hint(PropertyHint p_hint) {
|
||||
data->hint = p_hint;
|
||||
}
|
||||
|
||||
PropertyHint BBVariable::get_hint() const {
|
||||
return data->hint;
|
||||
}
|
||||
|
||||
void BBVariable::set_hint_string(const String &p_hint_string) {
|
||||
data->hint_string = p_hint_string;
|
||||
}
|
||||
|
||||
String BBVariable::get_hint_string() const {
|
||||
return data->hint_string;
|
||||
}
|
||||
|
||||
BBVariable BBVariable::duplicate() const {
|
||||
BBVariable var;
|
||||
var.data->hint = data->hint;
|
||||
var.data->hint_string = data->hint_string;
|
||||
var.data->type = data->type;
|
||||
var.data->value = data->value;
|
||||
return var;
|
||||
}
|
||||
|
||||
bool BBVariable::is_same_prop_info(const BBVariable &p_other) const {
|
||||
if (data->type != p_other.data->type) {
|
||||
return false;
|
||||
}
|
||||
if (data->hint != p_other.data->hint) {
|
||||
return false;
|
||||
}
|
||||
if (data->hint_string != p_other.data->hint_string) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BBVariable::copy_prop_info(const BBVariable &p_other) {
|
||||
data->type = p_other.data->type;
|
||||
data->hint = p_other.data->hint;
|
||||
data->hint_string = p_other.data->hint_string;
|
||||
}
|
||||
|
||||
bool BBVariable::operator==(const BBVariable &p_var) const {
|
||||
if (data == p_var.data) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!data || !p_var.data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data->type != p_var.data->type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data->hint != p_var.data->hint) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data->value != p_var.data->value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data->hint_string != p_var.data->hint_string) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BBVariable::operator!=(const BBVariable &p_var) const {
|
||||
return !(*this == p_var);
|
||||
}
|
||||
|
||||
void BBVariable::operator=(const BBVariable &p_var) {
|
||||
if (this == &p_var) {
|
||||
return;
|
||||
}
|
||||
|
||||
unref();
|
||||
|
||||
if (p_var.data && p_var.data->refcount.ref()) {
|
||||
data = p_var.data;
|
||||
}
|
||||
}
|
||||
|
||||
BBVariable::BBVariable(const BBVariable &p_var) {
|
||||
if (p_var.data && p_var.data->refcount.ref()) {
|
||||
data = p_var.data;
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
unref();
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/**
|
||||
* bb_variable.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2024 Serhii Snitsaruk
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#ifndef BB_VARIABLE_H
|
||||
#define BB_VARIABLE_H
|
||||
|
||||
#ifdef LIMBOAI_MODULE
|
||||
#include "core/object/object.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
#include "core/variant/variant.h"
|
||||
#endif // LIMBOAI_MODULE
|
||||
|
||||
#ifdef LIMBOAI_GDEXTENSION
|
||||
#include "godot_cpp/core/defs.hpp"
|
||||
#include "godot_cpp/templates/safe_refcount.hpp"
|
||||
#include "godot_cpp/variant/variant.hpp"
|
||||
using namespace godot;
|
||||
#endif // LIMBOAI_GDEXTENSION
|
||||
|
||||
class BBVariable {
|
||||
private:
|
||||
struct Data {
|
||||
SafeRefCount refcount;
|
||||
Variant value;
|
||||
Variant::Type type = Variant::NIL;
|
||||
PropertyHint hint = PropertyHint::PROPERTY_HINT_NONE;
|
||||
String hint_string;
|
||||
// bool bound = false;
|
||||
// uint64_t bound_object = 0;
|
||||
// StringName bound_property;
|
||||
};
|
||||
|
||||
Data *data = nullptr;
|
||||
void unref();
|
||||
// void init_ref();
|
||||
|
||||
public:
|
||||
void set_value(const Variant &p_value);
|
||||
Variant get_value() const;
|
||||
|
||||
void set_type(Variant::Type p_type);
|
||||
Variant::Type get_type() const;
|
||||
|
||||
void set_hint(PropertyHint p_hint);
|
||||
PropertyHint get_hint() const;
|
||||
|
||||
void set_hint_string(const String &p_hint_string);
|
||||
String get_hint_string() const;
|
||||
|
||||
BBVariable duplicate() const;
|
||||
|
||||
bool is_same_prop_info(const BBVariable &p_other) const;
|
||||
void copy_prop_info(const BBVariable &p_other);
|
||||
|
||||
// bool is_bound() { return bound; }
|
||||
|
||||
// void bind(Node *p_root, NodePath p_path);
|
||||
// void unbind();
|
||||
|
||||
bool operator==(const BBVariable &p_var) const;
|
||||
bool operator!=(const BBVariable &p_var) const;
|
||||
void operator=(const BBVariable &p_var);
|
||||
|
||||
BBVariable(const BBVariable &p_var);
|
||||
BBVariable(Variant::Type p_type = Variant::Type::NIL, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = "");
|
||||
~BBVariable();
|
||||
};
|
||||
|
||||
#endif // BB_VARIABLE_H
|
|
@ -22,63 +22,71 @@
|
|||
#include <godot_cpp/classes/ref.hpp>
|
||||
#include <godot_cpp/classes/ref_counted.hpp>
|
||||
#include <godot_cpp/core/object.hpp>
|
||||
#include <godot_cpp/variant/dictionary.hpp>
|
||||
using namespace godot;
|
||||
#endif
|
||||
|
||||
Ref<Blackboard> Blackboard::top() const {
|
||||
Ref<Blackboard> bb(this);
|
||||
while (bb->get_parent_scope().is_valid()) {
|
||||
bb = bb->get_parent_scope();
|
||||
while (bb->get_parent().is_valid()) {
|
||||
bb = bb->get_parent();
|
||||
}
|
||||
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) {
|
||||
if (data.has(p_name)) {
|
||||
// Not checking type - allowing duck-typing.
|
||||
data[p_name].set_value(p_value);
|
||||
} else {
|
||||
BBVariable var(p_value.get_type());
|
||||
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 (const KeyValue<String, BBVariable> &kv : data) {
|
||||
BBVariable var = kv.value;
|
||||
if (var.get_value().get_type() == Variant::NODE_PATH) {
|
||||
Node *fetched_node = p_node->get_node_or_null(var.get_value());
|
||||
if (fetched_node != nullptr) {
|
||||
data[keys[i]] = fetched_node;
|
||||
var.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("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("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);
|
||||
ClassDB::bind_method(D_METHOD("get_parent_scope"), &Blackboard::get_parent);
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -12,10 +12,11 @@
|
|||
#ifndef BLACKBOARD_H
|
||||
#define BLACKBOARD_H
|
||||
|
||||
#include "bb_variable.h"
|
||||
|
||||
#ifdef LIMBOAI_MODULE
|
||||
#include "core/object/object.h"
|
||||
#include "core/object/ref_counted.h"
|
||||
#include "core/variant/dictionary.h"
|
||||
#include "core/variant/variant.h"
|
||||
#include "scene/main/node.h"
|
||||
#endif // LIMBOAI_MODULE
|
||||
|
@ -25,7 +26,7 @@
|
|||
#include <godot_cpp/classes/ref.hpp>
|
||||
#include <godot_cpp/classes/ref_counted.hpp>
|
||||
#include <godot_cpp/core/object.hpp>
|
||||
#include <godot_cpp/variant/dictionary.hpp>
|
||||
#include <godot_cpp/templates/hash_map.hpp>
|
||||
using namespace godot;
|
||||
#endif // LIMBOAI_GDEXTENSION
|
||||
|
||||
|
@ -33,27 +34,28 @@ class Blackboard : public RefCounted {
|
|||
GDCLASS(Blackboard, RefCounted);
|
||||
|
||||
private:
|
||||
Dictionary data;
|
||||
HashMap<String, BBVariable> data;
|
||||
Ref<Blackboard> 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<Blackboard> &p_blackboard) { parent = p_blackboard; }
|
||||
Ref<Blackboard> get_parent_scope() const { return parent; }
|
||||
void set_parent(const Ref<Blackboard> &p_blackboard) { parent = p_blackboard; }
|
||||
Ref<Blackboard> get_parent() const { return parent; }
|
||||
|
||||
Ref<Blackboard> 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: Add serialization API.
|
||||
};
|
||||
|
||||
#endif // BLACKBOARD_H
|
|
@ -0,0 +1,269 @@
|
|||
/**
|
||||
* blackboard_plan.cpp
|
||||
* =============================================================================
|
||||
* Copyright 2021-2024 Serhii Snitsaruk
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#include "blackboard_plan.h"
|
||||
|
||||
bool BlackboardPlan::_set(const StringName &p_name, const Variant &p_value) {
|
||||
String prop_name = p_name;
|
||||
|
||||
// * Editor
|
||||
if (var_map.has(prop_name)) {
|
||||
var_map[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 (!var_map.has(var_name) && what == "name") {
|
||||
add_var(var_name, BBVariable());
|
||||
}
|
||||
if (what == "name") {
|
||||
// We don't store variable name with the variable.
|
||||
} else if (what == "type") {
|
||||
var_map[var_name].set_type((Variant::Type)(int)p_value);
|
||||
} else if (what == "value") {
|
||||
var_map[var_name].set_value(p_value);
|
||||
} else if (what == "hint") {
|
||||
var_map[var_name].set_hint((PropertyHint)(int)p_value);
|
||||
} else if (what == "hint_string") {
|
||||
var_map[var_name].set_hint_string(p_value);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BlackboardPlan::_get(const StringName &p_name, Variant &r_ret) const {
|
||||
String prop_name = p_name;
|
||||
|
||||
// * Editor
|
||||
if (var_map.has(prop_name)) {
|
||||
r_ret = var_map[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(!var_map.has(var_name), false);
|
||||
|
||||
if (what == "name") {
|
||||
r_ret = var_name;
|
||||
} else if (what == "type") {
|
||||
r_ret = var_map[var_name].get_type();
|
||||
} else if (what == "value") {
|
||||
r_ret = var_map[var_name].get_value();
|
||||
} else if (what == "hint") {
|
||||
r_ret = var_map[var_name].get_hint();
|
||||
} else if (what == "hint_string") {
|
||||
r_ret = var_map[var_name].get_hint_string();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BlackboardPlan::_get_property_list(List<PropertyInfo> *p_list) const {
|
||||
for (const Pair<String, BBVariable> &p : var_list) {
|
||||
String var_name = p.first;
|
||||
BBVariable var = p.second;
|
||||
|
||||
// * Editor
|
||||
if (!is_derived() || !var_name.begins_with("_")) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
bool BlackboardPlan::_property_can_revert(const StringName &p_name) const {
|
||||
return base.is_valid() && base->var_map.has(p_name);
|
||||
}
|
||||
|
||||
bool BlackboardPlan::_property_get_revert(const StringName &p_name, Variant &r_property) const {
|
||||
if (base->var_map.has(p_name)) {
|
||||
r_property = base->var_map[p_name].get_value();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void BlackboardPlan::set_base_plan(const Ref<BlackboardPlan> &p_base) {
|
||||
base = p_base;
|
||||
sync_with_base_plan();
|
||||
}
|
||||
|
||||
void BlackboardPlan::add_var(const String &p_name, const BBVariable &p_var) {
|
||||
ERR_FAIL_COND(var_map.has(p_name));
|
||||
var_map.insert(p_name, p_var);
|
||||
var_list.push_back(Pair<String, BBVariable>(p_name, p_var));
|
||||
notify_property_list_changed();
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void BlackboardPlan::remove_var(const String &p_name) {
|
||||
ERR_FAIL_COND(!var_map.has(p_name));
|
||||
var_list.erase(Pair<String, BBVariable>(p_name, var_map[p_name]));
|
||||
var_map.erase(p_name);
|
||||
notify_property_list_changed();
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
BBVariable BlackboardPlan::get_var(const String &p_name) {
|
||||
ERR_FAIL_COND_V(!var_map.has(p_name), BBVariable());
|
||||
return var_map.get(p_name);
|
||||
}
|
||||
|
||||
Pair<String, BBVariable> BlackboardPlan::get_var_by_index(int p_index) {
|
||||
Pair<String, BBVariable> ret;
|
||||
ERR_FAIL_INDEX_V(p_index, (int)var_map.size(), ret);
|
||||
return var_list[p_index];
|
||||
}
|
||||
|
||||
PackedStringArray BlackboardPlan::list_vars() const {
|
||||
PackedStringArray ret;
|
||||
for (const Pair<String, BBVariable> &p : var_list) {
|
||||
ret.append(p.first);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
String BlackboardPlan::get_var_name(const BBVariable &p_var) const {
|
||||
for (const Pair<String, BBVariable> &p : var_list) {
|
||||
if (p.second == p_var) {
|
||||
return p.first;
|
||||
}
|
||||
}
|
||||
return String();
|
||||
}
|
||||
|
||||
void BlackboardPlan::rename_var(const String &p_name, const String &p_new_name) {
|
||||
ERR_FAIL_COND(p_new_name.is_empty());
|
||||
ERR_FAIL_COND(var_map.has(p_new_name));
|
||||
ERR_FAIL_COND(!var_map.has(p_name));
|
||||
|
||||
BBVariable var = var_map[p_name];
|
||||
Pair<String, BBVariable> new_entry(p_new_name, var);
|
||||
Pair<String, BBVariable> old_entry(p_name, var);
|
||||
var_list.find(old_entry)->set(new_entry);
|
||||
|
||||
var_map.erase(p_name);
|
||||
var_map.insert(p_new_name, var);
|
||||
|
||||
notify_property_list_changed();
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void BlackboardPlan::move_var(int p_index, int p_new_index) {
|
||||
ERR_FAIL_INDEX(p_index, (int)var_map.size());
|
||||
ERR_FAIL_INDEX(p_new_index, (int)var_map.size());
|
||||
|
||||
if (p_index == p_new_index) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Pair<String, BBVariable>>::Element *E = var_list.front();
|
||||
for (int i = 0; i < p_index; i++) {
|
||||
E = E->next();
|
||||
}
|
||||
List<Pair<String, BBVariable>>::Element *E2 = var_list.front();
|
||||
for (int i = 0; i < p_new_index; i++) {
|
||||
E2 = E2->next();
|
||||
}
|
||||
|
||||
var_list.move_before(E, E2);
|
||||
if (p_new_index > p_index) {
|
||||
var_list.move_before(E2, E);
|
||||
}
|
||||
|
||||
notify_property_list_changed();
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void BlackboardPlan::sync_with_base_plan() {
|
||||
if (base.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
|
||||
// Sync variables with the base plan.
|
||||
for (const Pair<String, BBVariable> &p : base->var_list) {
|
||||
const String &base_name = p.first;
|
||||
const BBVariable &base_var = p.second;
|
||||
|
||||
if (!var_map.has(base_name)) {
|
||||
add_var(base_name, base_var.duplicate());
|
||||
changed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
BBVariable var = var_map[base_name];
|
||||
if (!var.is_same_prop_info(base_var)) {
|
||||
var.copy_prop_info(base_var);
|
||||
changed = true;
|
||||
}
|
||||
if (var.get_value().get_type() != base_var.get_type()) {
|
||||
var.set_value(base_var.get_value());
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Erase variables that do not exist in the base plan.
|
||||
for (const Pair<String, BBVariable> &p : var_list) {
|
||||
if (!base->has_var(p.first)) {
|
||||
remove_var(p.first);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
notify_property_list_changed();
|
||||
emit_changed();
|
||||
}
|
||||
}
|
||||
|
||||
Ref<Blackboard> BlackboardPlan::create_blackboard() {
|
||||
Ref<Blackboard> bb = memnew(Blackboard);
|
||||
for (const Pair<String, BBVariable> &p : var_list) {
|
||||
bb->add_var(p.first, p.second.duplicate());
|
||||
}
|
||||
return bb;
|
||||
}
|
||||
|
||||
void BlackboardPlan::populate_blackboard(const Ref<Blackboard> &p_blackboard, bool overwrite) {
|
||||
for (const Pair<String, BBVariable> &p : var_list) {
|
||||
if (p_blackboard->has_var(p.first)) {
|
||||
if (overwrite) {
|
||||
p_blackboard->erase_var(p.first);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
p_blackboard->add_var(p.first, p.second.duplicate());
|
||||
}
|
||||
}
|
||||
|
||||
BlackboardPlan::BlackboardPlan() {
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
* blackboard_plan.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2024 Serhii Snitsaruk
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#ifndef BLACKBOARD_PLAN_H
|
||||
#define BLACKBOARD_PLAN_H
|
||||
|
||||
#include "bb_variable.h"
|
||||
#include "blackboard.h"
|
||||
|
||||
#ifdef LIMBOAI_MODULE
|
||||
#include "core/io/resource.h"
|
||||
#endif // LIMBOAI_MODULE
|
||||
|
||||
#ifdef LIMBOAI_GDEXTENSION
|
||||
#include <godot_cpp/classes/resource.hpp>
|
||||
using namespace godot;
|
||||
#endif // LIMBOAI_GDEXTENSION
|
||||
|
||||
class BlackboardPlan : public Resource {
|
||||
GDCLASS(BlackboardPlan, Resource);
|
||||
|
||||
private:
|
||||
List<Pair<String, BBVariable>> var_list;
|
||||
HashMap<String, BBVariable> var_map;
|
||||
|
||||
// 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,
|
||||
// and only the values can be different in those variables.
|
||||
Ref<BlackboardPlan> base;
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
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;
|
||||
bool _property_can_revert(const StringName &p_name) const;
|
||||
bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
|
||||
|
||||
public:
|
||||
void set_base_plan(const Ref<BlackboardPlan> &p_base);
|
||||
Ref<BlackboardPlan> get_base_plan() const { return base; }
|
||||
|
||||
void add_var(const String &p_name, const BBVariable &p_var);
|
||||
void remove_var(const String &p_name);
|
||||
BBVariable get_var(const String &p_name);
|
||||
Pair<String, BBVariable> get_var_by_index(int p_index);
|
||||
bool has_var(const String &p_name) { return var_map.has(p_name); }
|
||||
bool is_empty() const { return var_map.is_empty(); }
|
||||
int get_var_count() const { return var_map.size(); }
|
||||
|
||||
PackedStringArray list_vars() const;
|
||||
String get_var_name(const BBVariable &p_var) const;
|
||||
void rename_var(const String &p_name, const String &p_new_name);
|
||||
void move_var(int p_index, int p_new_index);
|
||||
|
||||
void sync_with_base_plan();
|
||||
bool is_derived() const { return base.is_valid(); }
|
||||
|
||||
Ref<Blackboard> create_blackboard();
|
||||
void populate_blackboard(const Ref<Blackboard> &p_blackboard, bool overwrite);
|
||||
|
||||
BlackboardPlan();
|
||||
};
|
||||
|
||||
#endif // BLACKBOARD_PLAN_H
|
|
@ -22,6 +22,24 @@
|
|||
#include "godot_cpp/core/error_macros.hpp"
|
||||
#endif // ! LIMBOAI_GDEXTENSION
|
||||
|
||||
void BehaviorTree::set_description(const String &p_value) {
|
||||
description = p_value;
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void BehaviorTree::set_blackboard_plan(const Ref<BlackboardPlan> &p_plan) {
|
||||
blackboard_plan = p_plan;
|
||||
if (blackboard_plan.is_null()) {
|
||||
blackboard_plan = Ref<BlackboardPlan>(memnew(BlackboardPlan));
|
||||
}
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void BehaviorTree::set_root_task(const Ref<BTTask> &p_value) {
|
||||
root_task = p_value;
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
Ref<BehaviorTree> BehaviorTree::clone() const {
|
||||
Ref<BehaviorTree> copy = duplicate(false);
|
||||
copy->set_path("");
|
||||
|
@ -47,6 +65,8 @@ Ref<BTTask> BehaviorTree::instantiate(Node *p_agent, const Ref<Blackboard> &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_plan", "p_plan"), &BehaviorTree::set_blackboard_plan);
|
||||
ClassDB::bind_method(D_METHOD("get_blackboard_plan"), &BehaviorTree::get_blackboard_plan);
|
||||
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);
|
||||
|
@ -54,5 +74,9 @@ void BehaviorTree::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("instantiate", "p_agent", "p_blackboard"), &BehaviorTree::instantiate);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "description", PROPERTY_HINT_MULTILINE_TEXT), "set_description", "get_description");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard_plan", PROPERTY_HINT_RESOURCE_TYPE, "BlackboardPlan", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT), "set_blackboard_plan", "get_blackboard_plan");
|
||||
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");
|
||||
}
|
||||
|
||||
BehaviorTree::BehaviorTree() {
|
||||
}
|
||||
|
|
|
@ -12,11 +12,11 @@
|
|||
#ifndef BEHAVIOR_TREE_H
|
||||
#define BEHAVIOR_TREE_H
|
||||
|
||||
#include "../blackboard/blackboard_plan.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<BlackboardPlan> blackboard_plan;
|
||||
Ref<BTTask> root_task;
|
||||
|
||||
protected:
|
||||
|
@ -39,21 +40,20 @@ public:
|
|||
virtual bool editor_can_reload_from_file() override { return false; }
|
||||
#endif
|
||||
|
||||
void set_description(String p_value) {
|
||||
description = p_value;
|
||||
emit_changed();
|
||||
}
|
||||
void set_description(const String &p_value);
|
||||
String get_description() const { return description; }
|
||||
|
||||
void set_root_task(const Ref<BTTask> &p_value) {
|
||||
root_task = p_value;
|
||||
emit_changed();
|
||||
}
|
||||
void set_blackboard_plan(const Ref<BlackboardPlan> &p_plan);
|
||||
Ref<BlackboardPlan> get_blackboard_plan() const { return blackboard_plan; }
|
||||
|
||||
void set_root_task(const Ref<BTTask> &p_value);
|
||||
Ref<BTTask> get_root_task() const { return root_task; }
|
||||
|
||||
Ref<BehaviorTree> clone() const;
|
||||
void copy_other(const Ref<BehaviorTree> &p_other);
|
||||
Ref<BTTask> instantiate(Node *p_agent, const Ref<Blackboard> &p_blackboard) const;
|
||||
|
||||
BehaviorTree();
|
||||
};
|
||||
|
||||
#endif // BEHAVIOR_TREE_H
|
||||
|
|
|
@ -63,11 +63,34 @@ void BTPlayer::_load_tree() {
|
|||
#endif
|
||||
}
|
||||
|
||||
void BTPlayer::_update_blackboard_plan() {
|
||||
if (blackboard_plan.is_null()) {
|
||||
blackboard_plan = Ref<BlackboardPlan>(memnew(BlackboardPlan));
|
||||
}
|
||||
blackboard_plan->set_base_plan(behavior_tree.is_valid() ? behavior_tree->get_blackboard_plan() : nullptr);
|
||||
}
|
||||
|
||||
void BTPlayer::set_behavior_tree(const Ref<BehaviorTree> &p_tree) {
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
if (behavior_tree.is_valid() && behavior_tree->is_connected(LW_NAME(changed), callable_mp(this, &BTPlayer::_update_blackboard_plan))) {
|
||||
behavior_tree->disconnect(LW_NAME(changed), callable_mp(this, &BTPlayer::_update_blackboard_plan));
|
||||
}
|
||||
if (p_tree.is_valid()) {
|
||||
p_tree->connect(LW_NAME(changed), callable_mp(this, &BTPlayer::_update_blackboard_plan));
|
||||
}
|
||||
behavior_tree = p_tree;
|
||||
if (Engine::get_singleton()->is_editor_hint() == false && get_owner()) {
|
||||
_update_blackboard_plan();
|
||||
} else {
|
||||
behavior_tree = p_tree;
|
||||
if (get_owner()) {
|
||||
_load_tree();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BTPlayer::set_blackboard_plan(const Ref<BlackboardPlan> &p_plan) {
|
||||
blackboard_plan = p_plan;
|
||||
_update_blackboard_plan();
|
||||
}
|
||||
|
||||
void BTPlayer::set_update_mode(UpdateMode p_mode) {
|
||||
|
@ -160,6 +183,12 @@ void BTPlayer::_notification(int p_notification) {
|
|||
} break;
|
||||
case NOTIFICATION_READY: {
|
||||
if (!Engine::get_singleton()->is_editor_hint()) {
|
||||
if (blackboard.is_null()) {
|
||||
blackboard = Ref<Blackboard>(memnew(Blackboard));
|
||||
}
|
||||
if (blackboard_plan.is_valid()) {
|
||||
blackboard_plan->populate_blackboard(blackboard, false);
|
||||
}
|
||||
if (behavior_tree.is_valid()) {
|
||||
_load_tree();
|
||||
}
|
||||
|
@ -169,18 +198,27 @@ void BTPlayer::_notification(int p_notification) {
|
|||
#endif
|
||||
}
|
||||
} break;
|
||||
#ifdef DEBUG_ENABLED
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (tree_instance.is_valid() && IS_DEBUGGER_ACTIVE()) {
|
||||
LimboDebugger::get_singleton()->register_bt_instance(tree_instance, get_path());
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
} break;
|
||||
case NOTIFICATION_EXIT_TREE: {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (tree_instance.is_valid() && IS_DEBUGGER_ACTIVE()) {
|
||||
LimboDebugger::get_singleton()->unregister_bt_instance(tree_instance, get_path());
|
||||
}
|
||||
} break;
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
if (behavior_tree.is_valid() && behavior_tree->is_connected(LW_NAME(changed), callable_mp(this, &BTPlayer::_update_blackboard_plan))) {
|
||||
behavior_tree->disconnect(LW_NAME(changed), callable_mp(this, &BTPlayer::_update_blackboard_plan));
|
||||
}
|
||||
}
|
||||
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,8 +234,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_plan", "p_plan"), &BTPlayer::set_blackboard_plan);
|
||||
ClassDB::bind_method(D_METHOD("get_blackboard_plan"), &BTPlayer::get_blackboard_plan);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("update", "p_delta"), &BTPlayer::update);
|
||||
ClassDB::bind_method(D_METHOD("restart"), &BTPlayer::restart);
|
||||
|
@ -207,7 +245,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_plan", PROPERTY_HINT_RESOURCE_TYPE, "BlackboardPlan", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT), "set_blackboard_plan", "get_blackboard_plan");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "prefetch_nodepath_vars"), "set_prefetch_nodepath_vars", "get_prefetch_nodepath_vars");
|
||||
|
||||
BIND_ENUM_CONSTANT(IDLE);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define BT_PLAYER_H
|
||||
|
||||
#include "../blackboard/blackboard.h"
|
||||
#include "../blackboard/blackboard_plan.h"
|
||||
#include "behavior_tree.h"
|
||||
#include "tasks/bt_task.h"
|
||||
|
||||
|
@ -36,6 +37,7 @@ public:
|
|||
|
||||
private:
|
||||
Ref<BehaviorTree> behavior_tree;
|
||||
Ref<BlackboardPlan> blackboard_plan;
|
||||
UpdateMode update_mode = UpdateMode::PHYSICS;
|
||||
bool active = true;
|
||||
Ref<Blackboard> blackboard;
|
||||
|
@ -45,19 +47,20 @@ private:
|
|||
Ref<BTTask> tree_instance;
|
||||
|
||||
void _load_tree();
|
||||
void _update_blackboard_plan();
|
||||
|
||||
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<BehaviorTree> &p_tree);
|
||||
Ref<BehaviorTree> get_behavior_tree() const { return behavior_tree; };
|
||||
|
||||
void set_blackboard_plan(const Ref<BlackboardPlan> &p_plan);
|
||||
Ref<BlackboardPlan> get_blackboard_plan() const { return blackboard_plan; }
|
||||
|
||||
void set_update_mode(UpdateMode p_mode);
|
||||
UpdateMode get_update_mode() const { return update_mode; }
|
||||
|
||||
|
|
|
@ -26,6 +26,25 @@
|
|||
#include <godot_cpp/classes/engine_debugger.hpp>
|
||||
#endif // LIMBOAI_GDEXTENSION
|
||||
|
||||
void BTState::set_behavior_tree(const Ref<BehaviorTree> &p_tree) {
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
if (behavior_tree.is_valid() && behavior_tree->is_connected(LW_NAME(changed), callable_mp(this, &BTState::_update_blackboard_plan))) {
|
||||
behavior_tree->disconnect(LW_NAME(changed), callable_mp(this, &BTState::_update_blackboard_plan));
|
||||
}
|
||||
if (p_tree.is_valid()) {
|
||||
p_tree->connect(LW_NAME(changed), callable_mp(this, &BTState::_update_blackboard_plan));
|
||||
}
|
||||
}
|
||||
behavior_tree = p_tree;
|
||||
}
|
||||
|
||||
void BTState::_update_blackboard_plan() {
|
||||
if (get_blackboard_plan().is_null()) {
|
||||
set_blackboard_plan(Ref<BlackboardPlan>(memnew(BlackboardPlan)));
|
||||
}
|
||||
get_blackboard_plan()->set_base_plan(behavior_tree.is_valid() ? behavior_tree->get_blackboard_plan() : nullptr);
|
||||
}
|
||||
|
||||
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());
|
||||
|
@ -53,22 +72,30 @@ void BTState::_update(double p_delta) {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
void BTState::_notification(int p_notification) {
|
||||
switch (p_notification) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
if (tree_instance.is_valid() && IS_DEBUGGER_ACTIVE()) {
|
||||
LimboDebugger::get_singleton()->register_bt_instance(tree_instance, get_path());
|
||||
}
|
||||
} break;
|
||||
#endif // DEBUG_ENABLED
|
||||
case NOTIFICATION_EXIT_TREE: {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (tree_instance.is_valid() && IS_DEBUGGER_ACTIVE()) {
|
||||
LimboDebugger::get_singleton()->unregister_bt_instance(tree_instance, get_path());
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
if (behavior_tree.is_valid() && behavior_tree->is_connected(LW_NAME(changed), callable_mp(this, &BTState::_update_blackboard_plan))) {
|
||||
behavior_tree->disconnect(LW_NAME(changed), callable_mp(this, &BTState::_update_blackboard_plan));
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
void BTState::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_behavior_tree", "p_value"), &BTState::set_behavior_tree);
|
||||
|
|
|
@ -26,6 +26,8 @@ private:
|
|||
String success_event;
|
||||
String failure_event;
|
||||
|
||||
void _update_blackboard_plan();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
|
@ -34,7 +36,7 @@ protected:
|
|||
virtual void _update(double p_delta) override;
|
||||
|
||||
public:
|
||||
void set_behavior_tree(const Ref<BehaviorTree> &p_value) { behavior_tree = p_value; }
|
||||
void set_behavior_tree(const Ref<BehaviorTree> &p_value);
|
||||
Ref<BehaviorTree> get_behavior_tree() const { return behavior_tree; }
|
||||
|
||||
void set_success_event(String p_success_event) { success_event = p_success_event; }
|
||||
|
@ -45,11 +47,8 @@ public:
|
|||
|
||||
BTState();
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
protected:
|
||||
void _notification(int p_notification);
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // BT_STATE_H
|
||||
|
|
|
@ -15,10 +15,14 @@ void BTNewScope::initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard)
|
|||
ERR_FAIL_COND(p_agent == nullptr);
|
||||
ERR_FAIL_COND(p_blackboard == nullptr);
|
||||
|
||||
Ref<Blackboard> bb = memnew(Blackboard);
|
||||
Ref<Blackboard> bb;
|
||||
if (blackboard_plan.is_valid()) {
|
||||
bb = blackboard_plan->create_blackboard();
|
||||
} else {
|
||||
bb = Ref<Blackboard>(memnew(Blackboard));
|
||||
}
|
||||
|
||||
bb->set_data(blackboard_data.duplicate());
|
||||
bb->set_parent_scope(p_blackboard);
|
||||
bb->set_parent(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_plan", "p_plan"), &BTNewScope::set_blackboard_plan);
|
||||
ClassDB::bind_method(D_METHOD("get_blackboard_plan"), &BTNewScope::get_blackboard_plan);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_blackboard_data"), "_set_blackboard_data", "_get_blackboard_data");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard_plan", PROPERTY_HINT_RESOURCE_TYPE, "BlackboardPlan", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT), "set_blackboard_plan", "get_blackboard_plan");
|
||||
}
|
||||
|
|
|
@ -14,18 +14,20 @@
|
|||
|
||||
#include "../bt_decorator.h"
|
||||
|
||||
#include "../../../blackboard/blackboard_plan.h"
|
||||
|
||||
class BTNewScope : public BTDecorator {
|
||||
GDCLASS(BTNewScope, BTDecorator);
|
||||
TASK_CATEGORY(Decorators);
|
||||
|
||||
private:
|
||||
Dictionary blackboard_data;
|
||||
Ref<BlackboardPlan> blackboard_plan;
|
||||
|
||||
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_plan(const Ref<BlackboardPlan> &p_plan) { blackboard_plan = p_plan; }
|
||||
Ref<BlackboardPlan> get_blackboard_plan() const { return blackboard_plan; }
|
||||
|
||||
virtual Status _tick(double p_delta) override;
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ def get_doc_classes():
|
|||
"BehaviorTree",
|
||||
"BehaviorTreeView",
|
||||
"Blackboard",
|
||||
"BlackboardPlan",
|
||||
"BT",
|
||||
"BTAction",
|
||||
"BTAlwaysFail",
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
[gd_resource type="BehaviorTree" load_steps=10 format=3 uid="uid://cjkqi41oagagd"]
|
||||
[gd_resource type="BehaviorTree" load_steps=11 format=3 uid="uid://cjkqi41oagagd"]
|
||||
|
||||
[ext_resource type="Script" path="res://demo/ai/tasks/arrive_pos.gd" id="1_rhs33"]
|
||||
|
||||
[sub_resource type="BlackboardPlan" id="BlackboardPlan_2hcqi"]
|
||||
var/speed/name = "speed"
|
||||
var/speed/type = 3
|
||||
var/speed/value = 200.0
|
||||
var/speed/hint = 1
|
||||
var/speed/hint_string = "10,1000,10"
|
||||
|
||||
[sub_resource type="BTAction" id="BTAction_3xal7"]
|
||||
script = ExtResource("1_rhs33")
|
||||
target_position_var = "wp"
|
||||
|
@ -36,4 +43,5 @@ duration = 3.0
|
|||
children = [SubResource("BTCooldown_gen0l")]
|
||||
|
||||
[resource]
|
||||
blackboard_plan = SubResource("BlackboardPlan_2hcqi")
|
||||
root_task = SubResource("BTSelector_5dclr")
|
||||
|
|
|
@ -24,5 +24,3 @@ func _ready() -> void:
|
|||
waypoints.reverse()
|
||||
for wp in waypoints:
|
||||
agent2.add_waypoint(wp.global_position)
|
||||
|
||||
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
[gd_scene load_steps=7 format=3 uid="uid://c26b8c8dndtop"]
|
||||
[gd_scene load_steps=8 format=3 uid="uid://c26b8c8dndtop"]
|
||||
|
||||
[ext_resource type="Script" path="res://demo/examples/waypoints/patrolling_agent.gd" id="1_5wwhb"]
|
||||
[ext_resource type="BehaviorTree" uid="uid://cjkqi41oagagd" path="res://demo/ai/trees/waypoints.tres" id="2_66y4v"]
|
||||
[ext_resource type="Texture2D" uid="uid://d0mht3ntak7e5" path="res://demo/godot.png" id="3_64ge2"]
|
||||
|
||||
[sub_resource type="BlackboardPlan" id="BlackboardPlan_b86q8"]
|
||||
var/speed/name = "speed"
|
||||
var/speed/type = 3
|
||||
var/speed/value = 300.0
|
||||
var/speed/hint = 1
|
||||
var/speed/hint_string = "10,1000,10"
|
||||
|
||||
[sub_resource type="Animation" id="Animation_5id00"]
|
||||
length = 0.001
|
||||
tracks/0/type = "value"
|
||||
|
@ -46,9 +53,7 @@ script = ExtResource("1_5wwhb")
|
|||
|
||||
[node name="BTPlayer" type="BTPlayer" parent="."]
|
||||
behavior_tree = ExtResource("2_66y4v")
|
||||
_blackboard_data = {
|
||||
"speed": 200.0
|
||||
}
|
||||
blackboard_plan = SubResource("BlackboardPlan_b86q8")
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||
texture = ExtResource("3_64ge2")
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
:github_url: hide
|
||||
|
||||
.. DO NOT EDIT THIS FILE!!!
|
||||
.. Generated automatically from Godot engine sources.
|
||||
.. Generator: https://github.com/godotengine/godot/tree/4.2/doc/tools/make_rst.py.
|
||||
.. XML source: https://github.com/godotengine/godot/tree/4.2/modules/limboai/doc_classes/BBFloat32Array.xml.
|
||||
|
||||
.. _class_BBFloat32Array:
|
||||
|
||||
BBFloat32Array
|
||||
==============
|
||||
|
||||
**Inherits:** :ref:`BBParam<class_BBParam>`
|
||||
|
||||
PackedFloat32Array-type parameter for :ref:`BehaviorTree<class_BehaviorTree>` tasks. See :ref:`BBParam<class_BBParam>`.
|
||||
|
||||
.. |virtual| replace:: :abbr:`virtual (This method should typically be overridden by the user to have any effect.)`
|
||||
.. |const| replace:: :abbr:`const (This method has no side effects. It doesn't modify any of the instance's member variables.)`
|
||||
.. |vararg| replace:: :abbr:`vararg (This method accepts any number of arguments after the ones described here.)`
|
||||
.. |constructor| replace:: :abbr:`constructor (This method is used to construct a type.)`
|
||||
.. |static| replace:: :abbr:`static (This method doesn't need an instance to be called, so it can be called directly using the class name.)`
|
||||
.. |operator| replace:: :abbr:`operator (This method describes a valid operator to use with this type as left-hand operand.)`
|
||||
.. |bitfield| replace:: :abbr:`BitField (This value is an integer composed as a bitmask of the following flags.)`
|
|
@ -0,0 +1,23 @@
|
|||
:github_url: hide
|
||||
|
||||
.. DO NOT EDIT THIS FILE!!!
|
||||
.. Generated automatically from Godot engine sources.
|
||||
.. Generator: https://github.com/godotengine/godot/tree/4.2/doc/tools/make_rst.py.
|
||||
.. XML source: https://github.com/godotengine/godot/tree/4.2/modules/limboai/doc_classes/BBFloat64Array.xml.
|
||||
|
||||
.. _class_BBFloat64Array:
|
||||
|
||||
BBFloat64Array
|
||||
==============
|
||||
|
||||
**Inherits:** :ref:`BBParam<class_BBParam>`
|
||||
|
||||
PackedFloat64Array-type parameter for :ref:`BehaviorTree<class_BehaviorTree>` tasks. See :ref:`BBParam<class_BBParam>`.
|
||||
|
||||
.. |virtual| replace:: :abbr:`virtual (This method should typically be overridden by the user to have any effect.)`
|
||||
.. |const| replace:: :abbr:`const (This method has no side effects. It doesn't modify any of the instance's member variables.)`
|
||||
.. |vararg| replace:: :abbr:`vararg (This method accepts any number of arguments after the ones described here.)`
|
||||
.. |constructor| replace:: :abbr:`constructor (This method is used to construct a type.)`
|
||||
.. |static| replace:: :abbr:`static (This method doesn't need an instance to be called, so it can be called directly using the class name.)`
|
||||
.. |operator| replace:: :abbr:`operator (This method describes a valid operator to use with this type as left-hand operand.)`
|
||||
.. |bitfield| replace:: :abbr:`BitField (This value is an integer composed as a bitmask of the following flags.)`
|
|
@ -0,0 +1,23 @@
|
|||
:github_url: hide
|
||||
|
||||
.. DO NOT EDIT THIS FILE!!!
|
||||
.. Generated automatically from Godot engine sources.
|
||||
.. Generator: https://github.com/godotengine/godot/tree/4.2/doc/tools/make_rst.py.
|
||||
.. XML source: https://github.com/godotengine/godot/tree/4.2/modules/limboai/doc_classes/BBInt32Array.xml.
|
||||
|
||||
.. _class_BBInt32Array:
|
||||
|
||||
BBInt32Array
|
||||
============
|
||||
|
||||
**Inherits:** :ref:`BBParam<class_BBParam>`
|
||||
|
||||
PackedInt32Array-type parameter for :ref:`BehaviorTree<class_BehaviorTree>` tasks. See :ref:`BBParam<class_BBParam>`.
|
||||
|
||||
.. |virtual| replace:: :abbr:`virtual (This method should typically be overridden by the user to have any effect.)`
|
||||
.. |const| replace:: :abbr:`const (This method has no side effects. It doesn't modify any of the instance's member variables.)`
|
||||
.. |vararg| replace:: :abbr:`vararg (This method accepts any number of arguments after the ones described here.)`
|
||||
.. |constructor| replace:: :abbr:`constructor (This method is used to construct a type.)`
|
||||
.. |static| replace:: :abbr:`static (This method doesn't need an instance to be called, so it can be called directly using the class name.)`
|
||||
.. |operator| replace:: :abbr:`operator (This method describes a valid operator to use with this type as left-hand operand.)`
|
||||
.. |bitfield| replace:: :abbr:`BitField (This value is an integer composed as a bitmask of the following flags.)`
|
|
@ -0,0 +1,23 @@
|
|||
:github_url: hide
|
||||
|
||||
.. DO NOT EDIT THIS FILE!!!
|
||||
.. Generated automatically from Godot engine sources.
|
||||
.. Generator: https://github.com/godotengine/godot/tree/4.2/doc/tools/make_rst.py.
|
||||
.. XML source: https://github.com/godotengine/godot/tree/4.2/modules/limboai/doc_classes/BBInt64Array.xml.
|
||||
|
||||
.. _class_BBInt64Array:
|
||||
|
||||
BBInt64Array
|
||||
============
|
||||
|
||||
**Inherits:** :ref:`BBParam<class_BBParam>`
|
||||
|
||||
PackedInt64Array-type parameter for :ref:`BehaviorTree<class_BehaviorTree>` tasks. See :ref:`BBParam<class_BBParam>`.
|
||||
|
||||
.. |virtual| replace:: :abbr:`virtual (This method should typically be overridden by the user to have any effect.)`
|
||||
.. |const| replace:: :abbr:`const (This method has no side effects. It doesn't modify any of the instance's member variables.)`
|
||||
.. |vararg| replace:: :abbr:`vararg (This method accepts any number of arguments after the ones described here.)`
|
||||
.. |constructor| replace:: :abbr:`constructor (This method is used to construct a type.)`
|
||||
.. |static| replace:: :abbr:`static (This method doesn't need an instance to be called, so it can be called directly using the class name.)`
|
||||
.. |operator| replace:: :abbr:`operator (This method describes a valid operator to use with this type as left-hand operand.)`
|
||||
.. |bitfield| replace:: :abbr:`BitField (This value is an integer composed as a bitmask of the following flags.)`
|
|
@ -12,7 +12,7 @@ BBParam
|
|||
|
||||
**Inherits:**
|
||||
|
||||
**Inherited By:** :ref:`BBAabb<class_BBAabb>`, :ref:`BBArray<class_BBArray>`, :ref:`BBBasis<class_BBBasis>`, :ref:`BBBool<class_BBBool>`, :ref:`BBByteArray<class_BBByteArray>`, :ref:`BBColor<class_BBColor>`, :ref:`BBColorArray<class_BBColorArray>`, :ref:`BBDictionary<class_BBDictionary>`, :ref:`BBFloat<class_BBFloat>`, :ref:`BBFloatArray<class_BBFloatArray>`, :ref:`BBInt<class_BBInt>`, :ref:`BBIntArray<class_BBIntArray>`, :ref:`BBNode<class_BBNode>`, :ref:`BBPlane<class_BBPlane>`, :ref:`BBQuaternion<class_BBQuaternion>`, :ref:`BBRect2<class_BBRect2>`, :ref:`BBRect2i<class_BBRect2i>`, :ref:`BBString<class_BBString>`, :ref:`BBStringArray<class_BBStringArray>`, :ref:`BBStringName<class_BBStringName>`, :ref:`BBTransform2D<class_BBTransform2D>`, :ref:`BBTransform3D<class_BBTransform3D>`, :ref:`BBVariant<class_BBVariant>`, :ref:`BBVector2<class_BBVector2>`, :ref:`BBVector2Array<class_BBVector2Array>`, :ref:`BBVector2i<class_BBVector2i>`, :ref:`BBVector3<class_BBVector3>`, :ref:`BBVector3Array<class_BBVector3Array>`, :ref:`BBVector3i<class_BBVector3i>`, :ref:`BBVector4<class_BBVector4>`, :ref:`BBVector4i<class_BBVector4i>`
|
||||
**Inherited By:** :ref:`BBAabb<class_BBAabb>`, :ref:`BBArray<class_BBArray>`, :ref:`BBBasis<class_BBBasis>`, :ref:`BBBool<class_BBBool>`, :ref:`BBByteArray<class_BBByteArray>`, :ref:`BBColor<class_BBColor>`, :ref:`BBColorArray<class_BBColorArray>`, :ref:`BBDictionary<class_BBDictionary>`, :ref:`BBFloat<class_BBFloat>`, :ref:`BBFloat32Array<class_BBFloat32Array>`, :ref:`BBFloat64Array<class_BBFloat64Array>`, :ref:`BBInt<class_BBInt>`, :ref:`BBInt32Array<class_BBInt32Array>`, :ref:`BBInt64Array<class_BBInt64Array>`, :ref:`BBNode<class_BBNode>`, :ref:`BBPlane<class_BBPlane>`, :ref:`BBProjection<class_BBProjection>`, :ref:`BBQuaternion<class_BBQuaternion>`, :ref:`BBRect2<class_BBRect2>`, :ref:`BBRect2i<class_BBRect2i>`, :ref:`BBString<class_BBString>`, :ref:`BBStringArray<class_BBStringArray>`, :ref:`BBStringName<class_BBStringName>`, :ref:`BBTransform2D<class_BBTransform2D>`, :ref:`BBTransform3D<class_BBTransform3D>`, :ref:`BBVariant<class_BBVariant>`, :ref:`BBVector2<class_BBVector2>`, :ref:`BBVector2Array<class_BBVector2Array>`, :ref:`BBVector2i<class_BBVector2i>`, :ref:`BBVector3<class_BBVector3>`, :ref:`BBVector3Array<class_BBVector3Array>`, :ref:`BBVector3i<class_BBVector3i>`, :ref:`BBVector4<class_BBVector4>`, :ref:`BBVector4i<class_BBVector4i>`
|
||||
|
||||
A base class for LimboAI typed parameters.
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
:github_url: hide
|
||||
|
||||
.. DO NOT EDIT THIS FILE!!!
|
||||
.. Generated automatically from Godot engine sources.
|
||||
.. Generator: https://github.com/godotengine/godot/tree/4.2/doc/tools/make_rst.py.
|
||||
.. XML source: https://github.com/godotengine/godot/tree/4.2/modules/limboai/doc_classes/BBProjection.xml.
|
||||
|
||||
.. _class_BBProjection:
|
||||
|
||||
BBProjection
|
||||
============
|
||||
|
||||
**Inherits:** :ref:`BBParam<class_BBParam>`
|
||||
|
||||
Projection-type parameter for :ref:`BehaviorTree<class_BehaviorTree>` tasks. See :ref:`BBParam<class_BBParam>`.
|
||||
|
||||
.. |virtual| replace:: :abbr:`virtual (This method should typically be overridden by the user to have any effect.)`
|
||||
.. |const| replace:: :abbr:`const (This method has no side effects. It doesn't modify any of the instance's member variables.)`
|
||||
.. |vararg| replace:: :abbr:`vararg (This method accepts any number of arguments after the ones described here.)`
|
||||
.. |constructor| replace:: :abbr:`constructor (This method is used to construct a type.)`
|
||||
.. |static| replace:: :abbr:`static (This method doesn't need an instance to be called, so it can be called directly using the class name.)`
|
||||
.. |operator| replace:: :abbr:`operator (This method describes a valid operator to use with this type as left-hand operand.)`
|
||||
.. |bitfield| replace:: :abbr:`BitField (This value is an integer composed as a bitmask of the following flags.)`
|
|
@ -41,9 +41,11 @@ Properties
|
|||
.. table::
|
||||
:widths: auto
|
||||
|
||||
+--------+-------------------------------------------------------------+--------+
|
||||
+---------------------------------------------+---------------------------------------------------------------------+--------+
|
||||
| :ref:`BlackboardPlan<class_BlackboardPlan>` | :ref:`blackboard_plan<class_BehaviorTree_property_blackboard_plan>` | |
|
||||
+---------------------------------------------+---------------------------------------------------------------------+--------+
|
||||
| String | :ref:`description<class_BehaviorTree_property_description>` | ``""`` |
|
||||
+--------+-------------------------------------------------------------+--------+
|
||||
+---------------------------------------------+---------------------------------------------------------------------+--------+
|
||||
|
||||
.. rst-class:: classref-reftable-group
|
||||
|
||||
|
@ -74,6 +76,23 @@ Methods
|
|||
Property Descriptions
|
||||
---------------------
|
||||
|
||||
.. _class_BehaviorTree_property_blackboard_plan:
|
||||
|
||||
.. rst-class:: classref-property
|
||||
|
||||
:ref:`BlackboardPlan<class_BlackboardPlan>` **blackboard_plan**
|
||||
|
||||
.. rst-class:: classref-property-setget
|
||||
|
||||
- void **set_blackboard_plan** **(** :ref:`BlackboardPlan<class_BlackboardPlan>` value **)**
|
||||
- :ref:`BlackboardPlan<class_BlackboardPlan>` **get_blackboard_plan** **(** **)**
|
||||
|
||||
Stores and manages variables that will be used in constructing new :ref:`Blackboard<class_Blackboard>` instances.
|
||||
|
||||
.. rst-class:: classref-item-separator
|
||||
|
||||
----
|
||||
|
||||
.. _class_BehaviorTree_property_description:
|
||||
|
||||
.. rst-class:: classref-property
|
||||
|
|
|
@ -34,23 +34,19 @@ Methods
|
|||
:widths: auto
|
||||
|
||||
+-------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
|
||||
| void | :ref:`erase_var<class_Blackboard_method_erase_var>` **(** Variant p_key **)** |
|
||||
+-------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Dictionary | :ref:`get_data<class_Blackboard_method_get_data>` **(** **)** |const| |
|
||||
| void | :ref:`erase_var<class_Blackboard_method_erase_var>` **(** String p_name **)** |
|
||||
+-------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
|
||||
| :ref:`Blackboard<class_Blackboard>` | :ref:`get_parent_scope<class_Blackboard_method_get_parent_scope>` **(** **)** |const| |
|
||||
+-------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
|
||||
| Variant | :ref:`get_var<class_Blackboard_method_get_var>` **(** Variant p_key, Variant p_default=null **)** |const| |
|
||||
| Variant | :ref:`get_var<class_Blackboard_method_get_var>` **(** String p_name, Variant p_default=null **)** |const| |
|
||||
+-------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
|
||||
| bool | :ref:`has_var<class_Blackboard_method_has_var>` **(** Variant p_key **)** |const| |
|
||||
| bool | :ref:`has_var<class_Blackboard_method_has_var>` **(** String p_name **)** |const| |
|
||||
+-------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
|
||||
| void | :ref:`prefetch_nodepath_vars<class_Blackboard_method_prefetch_nodepath_vars>` **(** Node p_node **)** |
|
||||
+-------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
|
||||
| void | :ref:`set_data<class_Blackboard_method_set_data>` **(** Dictionary p_data **)** |
|
||||
+-------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
|
||||
| void | :ref:`set_parent_scope<class_Blackboard_method_set_parent_scope>` **(** :ref:`Blackboard<class_Blackboard>` p_blackboard **)** |
|
||||
+-------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
|
||||
| void | :ref:`set_var<class_Blackboard_method_set_var>` **(** Variant p_key, Variant p_value **)** |
|
||||
| void | :ref:`set_var<class_Blackboard_method_set_var>` **(** String p_name, Variant p_value **)** |
|
||||
+-------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
|
||||
| :ref:`Blackboard<class_Blackboard>` | :ref:`top<class_Blackboard_method_top>` **(** **)** |const| |
|
||||
+-------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
|
||||
|
@ -68,7 +64,7 @@ Method Descriptions
|
|||
|
||||
.. rst-class:: classref-method
|
||||
|
||||
void **erase_var** **(** Variant p_key **)**
|
||||
void **erase_var** **(** String p_name **)**
|
||||
|
||||
Removes a variable by its name.
|
||||
|
||||
|
@ -76,18 +72,6 @@ Removes a variable by its name.
|
|||
|
||||
----
|
||||
|
||||
.. _class_Blackboard_method_get_data:
|
||||
|
||||
.. rst-class:: classref-method
|
||||
|
||||
Dictionary **get_data** **(** **)** |const|
|
||||
|
||||
Returns Blackboard data as a ``Dictionary``.
|
||||
|
||||
.. rst-class:: classref-item-separator
|
||||
|
||||
----
|
||||
|
||||
.. _class_Blackboard_method_get_parent_scope:
|
||||
|
||||
.. rst-class:: classref-method
|
||||
|
@ -104,7 +88,7 @@ Returns a Blackboard that serves as the parent scope for this instance.
|
|||
|
||||
.. rst-class:: classref-method
|
||||
|
||||
Variant **get_var** **(** Variant p_key, Variant p_default=null **)** |const|
|
||||
Variant **get_var** **(** String p_name, Variant p_default=null **)** |const|
|
||||
|
||||
Returns variable value.
|
||||
|
||||
|
@ -116,7 +100,7 @@ Returns variable value.
|
|||
|
||||
.. rst-class:: classref-method
|
||||
|
||||
bool **has_var** **(** Variant p_key **)** |const|
|
||||
bool **has_var** **(** String p_name **)** |const|
|
||||
|
||||
Returns ``true`` if the Blackboard contains the ``p_key`` variable, including the parent scopes.
|
||||
|
||||
|
@ -136,18 +120,6 @@ If ``true``, any ``NodePath`` variables in the **Blackboard** are replaced with
|
|||
|
||||
----
|
||||
|
||||
.. _class_Blackboard_method_set_data:
|
||||
|
||||
.. rst-class:: classref-method
|
||||
|
||||
void **set_data** **(** Dictionary p_data **)**
|
||||
|
||||
Overwrites Blackboard data, replacing any previously stored variables within current scope. Use with caution.
|
||||
|
||||
.. rst-class:: classref-item-separator
|
||||
|
||||
----
|
||||
|
||||
.. _class_Blackboard_method_set_parent_scope:
|
||||
|
||||
.. rst-class:: classref-method
|
||||
|
@ -164,7 +136,7 @@ Assigns the parent scope. If a value isn't in the current Blackboard scope, it w
|
|||
|
||||
.. rst-class:: classref-method
|
||||
|
||||
void **set_var** **(** Variant p_key, Variant p_value **)**
|
||||
void **set_var** **(** String p_name, Variant p_value **)**
|
||||
|
||||
Assigns a value to a Blackboard variable.
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
:github_url: hide
|
||||
|
||||
.. DO NOT EDIT THIS FILE!!!
|
||||
.. Generated automatically from Godot engine sources.
|
||||
.. Generator: https://github.com/godotengine/godot/tree/4.2/doc/tools/make_rst.py.
|
||||
.. XML source: https://github.com/godotengine/godot/tree/4.2/modules/limboai/doc_classes/BlackboardPlan.xml.
|
||||
|
||||
.. _class_BlackboardPlan:
|
||||
|
||||
BlackboardPlan
|
||||
==============
|
||||
|
||||
**Inherits:**
|
||||
|
||||
Stores and manages variables that will be used in constructing new :ref:`Blackboard<class_Blackboard>` instances.
|
||||
|
||||
.. |virtual| replace:: :abbr:`virtual (This method should typically be overridden by the user to have any effect.)`
|
||||
.. |const| replace:: :abbr:`const (This method has no side effects. It doesn't modify any of the instance's member variables.)`
|
||||
.. |vararg| replace:: :abbr:`vararg (This method accepts any number of arguments after the ones described here.)`
|
||||
.. |constructor| replace:: :abbr:`constructor (This method is used to construct a type.)`
|
||||
.. |static| replace:: :abbr:`static (This method doesn't need an instance to be called, so it can be called directly using the class name.)`
|
||||
.. |operator| replace:: :abbr:`operator (This method describes a valid operator to use with this type as left-hand operand.)`
|
||||
.. |bitfield| replace:: :abbr:`BitField (This value is an integer composed as a bitmask of the following flags.)`
|
|
@ -33,9 +33,9 @@ Properties
|
|||
.. table::
|
||||
:widths: auto
|
||||
|
||||
+------------+---------------------------------------------------------------------+--------+
|
||||
| Dictionary | :ref:`_blackboard_data<class_BTNewScope_property__blackboard_data>` | ``{}`` |
|
||||
+------------+---------------------------------------------------------------------+--------+
|
||||
+---------------------------------------------+-------------------------------------------------------------------+
|
||||
| :ref:`BlackboardPlan<class_BlackboardPlan>` | :ref:`blackboard_plan<class_BTNewScope_property_blackboard_plan>` |
|
||||
+---------------------------------------------+-------------------------------------------------------------------+
|
||||
|
||||
.. rst-class:: classref-section-separator
|
||||
|
||||
|
@ -46,13 +46,18 @@ Properties
|
|||
Property Descriptions
|
||||
---------------------
|
||||
|
||||
.. _class_BTNewScope_property__blackboard_data:
|
||||
.. _class_BTNewScope_property_blackboard_plan:
|
||||
|
||||
.. rst-class:: classref-property
|
||||
|
||||
Dictionary **_blackboard_data** = ``{}``
|
||||
:ref:`BlackboardPlan<class_BlackboardPlan>` **blackboard_plan**
|
||||
|
||||
Data that is used to populate a new scope of the :ref:`Blackboard<class_Blackboard>`.
|
||||
.. rst-class:: classref-property-setget
|
||||
|
||||
- void **set_blackboard_plan** **(** :ref:`BlackboardPlan<class_BlackboardPlan>` value **)**
|
||||
- :ref:`BlackboardPlan<class_BlackboardPlan>` **get_blackboard_plan** **(** **)**
|
||||
|
||||
Stores and manages variables that will be used in constructing new :ref:`Blackboard<class_Blackboard>` instances.
|
||||
|
||||
.. |virtual| replace:: :abbr:`virtual (This method should typically be overridden by the user to have any effect.)`
|
||||
.. |const| replace:: :abbr:`const (This method has no side effects. It doesn't modify any of the instance's member variables.)`
|
||||
|
|
|
@ -38,6 +38,8 @@ Properties
|
|||
+---------------------------------------------+-------------------------------------------------------------------------------+-----------+
|
||||
| :ref:`Blackboard<class_Blackboard>` | :ref:`blackboard<class_BTPlayer_property_blackboard>` | |
|
||||
+---------------------------------------------+-------------------------------------------------------------------------------+-----------+
|
||||
| :ref:`BlackboardPlan<class_BlackboardPlan>` | :ref:`blackboard_plan<class_BTPlayer_property_blackboard_plan>` | |
|
||||
+---------------------------------------------+-------------------------------------------------------------------------------+-----------+
|
||||
| bool | :ref:`monitor_performance<class_BTPlayer_property_monitor_performance>` | ``false`` |
|
||||
+---------------------------------------------+-------------------------------------------------------------------------------+-----------+
|
||||
| bool | :ref:`prefetch_nodepath_vars<class_BTPlayer_property_prefetch_nodepath_vars>` | ``true`` |
|
||||
|
@ -193,6 +195,23 @@ Holds data shared by the behavior tree tasks. See :ref:`Blackboard<class_Blackbo
|
|||
|
||||
----
|
||||
|
||||
.. _class_BTPlayer_property_blackboard_plan:
|
||||
|
||||
.. rst-class:: classref-property
|
||||
|
||||
:ref:`BlackboardPlan<class_BlackboardPlan>` **blackboard_plan**
|
||||
|
||||
.. rst-class:: classref-property-setget
|
||||
|
||||
- void **set_blackboard_plan** **(** :ref:`BlackboardPlan<class_BlackboardPlan>` value **)**
|
||||
- :ref:`BlackboardPlan<class_BlackboardPlan>` **get_blackboard_plan** **(** **)**
|
||||
|
||||
Stores and manages variables that will be used in constructing new :ref:`Blackboard<class_Blackboard>` instances.
|
||||
|
||||
.. rst-class:: classref-item-separator
|
||||
|
||||
----
|
||||
|
||||
.. _class_BTPlayer_property_monitor_performance:
|
||||
|
||||
.. rst-class:: classref-property
|
||||
|
|
|
@ -35,13 +35,15 @@ Properties
|
|||
.. table::
|
||||
:widths: auto
|
||||
|
||||
+-------------------------------------+-----------------------------------------------------------------+
|
||||
+---------------------------------------------+-------------------------------------------------------------------+
|
||||
| String | :ref:`EVENT_FINISHED<class_LimboState_property_EVENT_FINISHED>` |
|
||||
+-------------------------------------+-----------------------------------------------------------------+
|
||||
+---------------------------------------------+-------------------------------------------------------------------+
|
||||
| Node | :ref:`agent<class_LimboState_property_agent>` |
|
||||
+-------------------------------------+-----------------------------------------------------------------+
|
||||
+---------------------------------------------+-------------------------------------------------------------------+
|
||||
| :ref:`Blackboard<class_Blackboard>` | :ref:`blackboard<class_LimboState_property_blackboard>` |
|
||||
+-------------------------------------+-----------------------------------------------------------------+
|
||||
+---------------------------------------------+-------------------------------------------------------------------+
|
||||
| :ref:`BlackboardPlan<class_BlackboardPlan>` | :ref:`blackboard_plan<class_LimboState_property_blackboard_plan>` |
|
||||
+---------------------------------------------+-------------------------------------------------------------------+
|
||||
|
||||
.. rst-class:: classref-reftable-group
|
||||
|
||||
|
@ -188,6 +190,23 @@ An agent associated with the state, assigned during initialization.
|
|||
|
||||
A key/value data store shared by states within the state machine to which this state belongs.
|
||||
|
||||
.. rst-class:: classref-item-separator
|
||||
|
||||
----
|
||||
|
||||
.. _class_LimboState_property_blackboard_plan:
|
||||
|
||||
.. rst-class:: classref-property
|
||||
|
||||
:ref:`BlackboardPlan<class_BlackboardPlan>` **blackboard_plan**
|
||||
|
||||
.. rst-class:: classref-property-setget
|
||||
|
||||
- void **set_blackboard_plan** **(** :ref:`BlackboardPlan<class_BlackboardPlan>` value **)**
|
||||
- :ref:`BlackboardPlan<class_BlackboardPlan>` **get_blackboard_plan** **(** **)**
|
||||
|
||||
Stores and manages variables that will be used in constructing new :ref:`Blackboard<class_Blackboard>` instances.
|
||||
|
||||
.. rst-class:: classref-section-separator
|
||||
|
||||
----
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
<tutorials>
|
||||
</tutorials>
|
||||
<members>
|
||||
<member name="_blackboard_data" type="Dictionary" setter="_set_blackboard_data" getter="_get_blackboard_data" default="{}">
|
||||
Data that is used to populate a new scope of the [Blackboard].
|
||||
<member name="blackboard_plan" type="BlackboardPlan" setter="set_blackboard_plan" getter="get_blackboard_plan">
|
||||
Stores and manages variables that will be used in constructing new [Blackboard] instances.
|
||||
</member>
|
||||
</members>
|
||||
</class>
|
||||
|
|
|
@ -40,6 +40,9 @@
|
|||
<member name="blackboard" type="Blackboard" setter="set_blackboard" getter="get_blackboard">
|
||||
Holds data shared by the behavior tree tasks. See [Blackboard].
|
||||
</member>
|
||||
<member name="blackboard_plan" type="BlackboardPlan" setter="set_blackboard_plan" getter="get_blackboard_plan">
|
||||
Stores and manages variables that will be used in constructing new [Blackboard] instances.
|
||||
</member>
|
||||
<member name="monitor_performance" type="bool" setter="_set_monitor_performance" getter="_get_monitor_performance" default="false">
|
||||
If [code]true[/code], adds a performance monitor to "Debugger->Monitors" for each instance of this [BTPlayer] node.
|
||||
</member>
|
||||
|
|
|
@ -51,6 +51,9 @@
|
|||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="blackboard_plan" type="BlackboardPlan" setter="set_blackboard_plan" getter="get_blackboard_plan">
|
||||
Stores and manages variables that will be used in constructing new [Blackboard] instances.
|
||||
</member>
|
||||
<member name="description" type="String" setter="set_description" getter="get_description" default="""">
|
||||
User-provided description of the BehaviorTree.
|
||||
</member>
|
||||
|
|
|
@ -13,17 +13,11 @@
|
|||
<methods>
|
||||
<method name="erase_var">
|
||||
<return type="void" />
|
||||
<param index="0" name="p_key" type="Variant" />
|
||||
<param index="0" name="p_name" type="String" />
|
||||
<description>
|
||||
Removes a variable by its name.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_data" qualifiers="const">
|
||||
<return type="Dictionary" />
|
||||
<description>
|
||||
Returns Blackboard data as a [Dictionary].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_parent_scope" qualifiers="const">
|
||||
<return type="Blackboard" />
|
||||
<description>
|
||||
|
@ -32,7 +26,7 @@
|
|||
</method>
|
||||
<method name="get_var" qualifiers="const">
|
||||
<return type="Variant" />
|
||||
<param index="0" name="p_key" type="Variant" />
|
||||
<param index="0" name="p_name" type="String" />
|
||||
<param index="1" name="p_default" type="Variant" default="null" />
|
||||
<description>
|
||||
Returns variable value.
|
||||
|
@ -40,7 +34,7 @@
|
|||
</method>
|
||||
<method name="has_var" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<param index="0" name="p_key" type="Variant" />
|
||||
<param index="0" name="p_name" type="String" />
|
||||
<description>
|
||||
Returns [code]true[/code] if the Blackboard contains the [param p_key] variable, including the parent scopes.
|
||||
</description>
|
||||
|
@ -52,13 +46,6 @@
|
|||
If [code]true[/code], any [NodePath] variables in the [Blackboard] are replaced with [Node] references when the tree is instantiated. References are retrieved by calling [method Node.get_node] on the agent instance.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_data">
|
||||
<return type="void" />
|
||||
<param index="0" name="p_data" type="Dictionary" />
|
||||
<description>
|
||||
Overwrites Blackboard data, replacing any previously stored variables within current scope. Use with caution.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_parent_scope">
|
||||
<return type="void" />
|
||||
<param index="0" name="p_blackboard" type="Blackboard" />
|
||||
|
@ -68,7 +55,7 @@
|
|||
</method>
|
||||
<method name="set_var">
|
||||
<return type="void" />
|
||||
<param index="0" name="p_key" type="Variant" />
|
||||
<param index="0" name="p_name" type="String" />
|
||||
<param index="1" name="p_value" type="Variant" />
|
||||
<description>
|
||||
Assigns a value to a Blackboard variable.
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="BlackboardPlan" inherits="Resource" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Stores and manages variables that will be used in constructing new [Blackboard] instances.
|
||||
</brief_description>
|
||||
<description>
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
</class>
|
|
@ -117,6 +117,9 @@
|
|||
<member name="blackboard" type="Blackboard" setter="" getter="get_blackboard">
|
||||
A key/value data store shared by states within the state machine to which this state belongs.
|
||||
</member>
|
||||
<member name="blackboard_plan" type="BlackboardPlan" setter="set_blackboard_plan" getter="get_blackboard_plan">
|
||||
Stores and manages variables that will be used in constructing new [Blackboard] instances.
|
||||
</member>
|
||||
</members>
|
||||
<signals>
|
||||
<signal name="entered">
|
||||
|
|
|
@ -0,0 +1,449 @@
|
|||
/**
|
||||
* blackboard_plan_editor.cpp
|
||||
* =============================================================================
|
||||
* Copyright 2021-2024 Serhii Snitsaruk
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#include "blackboard_plan_editor.h"
|
||||
|
||||
#include "../util/limbo_compat.h"
|
||||
#include "../util/limbo_string_names.h"
|
||||
#include "../util/limbo_utility.h"
|
||||
|
||||
#ifdef LIMBOAI_MODULE
|
||||
#include "editor/editor_interface.h"
|
||||
#include "editor/editor_scale.h"
|
||||
#include "scene/gui/line_edit.h"
|
||||
#include "scene/gui/panel_container.h"
|
||||
#include "scene/resources/style_box_flat.h"
|
||||
#endif // LIMBOAI_MODULE
|
||||
|
||||
#ifdef LIMBOAI_GDEXTENSION
|
||||
#include <godot_cpp/classes/button.hpp>
|
||||
#include <godot_cpp/classes/editor_interface.hpp>
|
||||
#include <godot_cpp/classes/h_box_container.hpp>
|
||||
#include <godot_cpp/classes/input.hpp>
|
||||
#include <godot_cpp/classes/input_event_mouse_motion.hpp>
|
||||
#include <godot_cpp/classes/label.hpp>
|
||||
#include <godot_cpp/classes/line_edit.hpp>
|
||||
#include <godot_cpp/classes/margin_container.hpp>
|
||||
#include <godot_cpp/classes/theme.hpp>
|
||||
using namespace godot;
|
||||
#endif // LIMBOAI_GDEXTENSION
|
||||
|
||||
void BlackboardPlanEditor::_add_var() {
|
||||
ERR_FAIL_NULL(plan);
|
||||
|
||||
int suffix = 1;
|
||||
String name = "var" + itos(suffix);
|
||||
while (plan->has_var(name)) {
|
||||
suffix += 1;
|
||||
name = "var" + itos(suffix);
|
||||
}
|
||||
|
||||
BBVariable var(Variant::Type::FLOAT);
|
||||
plan->add_var(name, var);
|
||||
_refresh();
|
||||
}
|
||||
|
||||
void BlackboardPlanEditor::_trash_var(int p_index) {
|
||||
ERR_FAIL_NULL(plan);
|
||||
String var_name = plan->get_var_by_index(p_index).first;
|
||||
plan->remove_var(var_name);
|
||||
_refresh();
|
||||
}
|
||||
|
||||
void BlackboardPlanEditor::_rename_var(const String &p_new_name, int p_index) {
|
||||
ERR_FAIL_NULL(plan);
|
||||
plan->rename_var(plan->get_var_by_index(p_index).first, p_new_name);
|
||||
}
|
||||
|
||||
void BlackboardPlanEditor::_change_var_type(Variant::Type p_new_type, int p_index) {
|
||||
ERR_FAIL_NULL(plan);
|
||||
plan->get_var_by_index(p_index).second.set_type(p_new_type);
|
||||
plan->notify_property_list_changed();
|
||||
_refresh();
|
||||
}
|
||||
|
||||
void BlackboardPlanEditor::_change_var_hint(PropertyHint p_new_hint, int p_index) {
|
||||
ERR_FAIL_NULL(plan);
|
||||
plan->get_var_by_index(p_index).second.set_hint(p_new_hint);
|
||||
plan->notify_property_list_changed();
|
||||
_refresh();
|
||||
}
|
||||
|
||||
void BlackboardPlanEditor::_change_var_hint_string(const String &p_new_hint_string, int p_index) {
|
||||
ERR_FAIL_NULL(plan);
|
||||
plan->get_var_by_index(p_index).second.set_hint_string(p_new_hint_string);
|
||||
plan->notify_property_list_changed();
|
||||
}
|
||||
|
||||
void BlackboardPlanEditor::edit_plan(const Ref<BlackboardPlan> &p_plan) {
|
||||
plan = p_plan;
|
||||
_refresh();
|
||||
}
|
||||
|
||||
void BlackboardPlanEditor::_show_button_popup(Button *p_button, PopupMenu *p_popup, int p_index) {
|
||||
ERR_FAIL_NULL(p_button);
|
||||
ERR_FAIL_NULL(p_popup);
|
||||
|
||||
Transform2D xform = p_button->get_screen_transform();
|
||||
Rect2 rect(xform.get_origin(), xform.get_scale() * p_button->get_size());
|
||||
rect.position.y += rect.size.height;
|
||||
rect.size.height = 0;
|
||||
p_popup->set_size(rect.size);
|
||||
p_popup->set_position(rect.position);
|
||||
|
||||
last_index = p_index;
|
||||
p_popup->popup();
|
||||
}
|
||||
|
||||
void BlackboardPlanEditor::_type_chosen(int id) {
|
||||
_change_var_type(Variant::Type(id), last_index);
|
||||
}
|
||||
|
||||
void BlackboardPlanEditor::_hint_chosen(int id) {
|
||||
_change_var_hint(PropertyHint(id), last_index);
|
||||
}
|
||||
|
||||
void BlackboardPlanEditor::_drag_button_down(Control *p_row) {
|
||||
drag_index = p_row->get_index();
|
||||
drag_start = drag_index;
|
||||
drag_mouse_y_delta = 0.0;
|
||||
Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED);
|
||||
}
|
||||
|
||||
void BlackboardPlanEditor::_drag_button_up() {
|
||||
Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
|
||||
plan->move_var(drag_start, drag_index);
|
||||
drag_index = -1;
|
||||
drag_start = -1;
|
||||
_refresh();
|
||||
}
|
||||
|
||||
void BlackboardPlanEditor::_drag_button_gui_input(const Ref<InputEvent> &p_event) {
|
||||
if (drag_index < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<InputEventMouseMotion> mm = p_event;
|
||||
if (mm.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
drag_mouse_y_delta += mm->get_relative().y;
|
||||
|
||||
if ((drag_index == 0 && drag_mouse_y_delta < 0.0) || (drag_index == (plan->get_var_count() - 1) && drag_mouse_y_delta > 0.0)) {
|
||||
drag_mouse_y_delta = 0.0;
|
||||
return;
|
||||
}
|
||||
|
||||
float required_distance = 30.0f * EDSCALE;
|
||||
if (ABS(drag_mouse_y_delta) > required_distance) {
|
||||
int drag_dir = drag_mouse_y_delta > 0.0f ? 1 : -1;
|
||||
drag_mouse_y_delta -= required_distance * drag_dir;
|
||||
|
||||
Control *row = Object::cast_to<Control>(rows_vbox->get_child(drag_index));
|
||||
Control *other_row = Object::cast_to<Control>(rows_vbox->get_child(drag_index + drag_dir));
|
||||
ERR_FAIL_NULL(row);
|
||||
ERR_FAIL_NULL(other_row);
|
||||
rows_vbox->move_child(row, drag_index + drag_dir);
|
||||
ADD_STYLEBOX_OVERRIDE(row, LW_NAME(panel), row->get_index() % 2 ? theme_cache.odd_style : theme_cache.even_style);
|
||||
ADD_STYLEBOX_OVERRIDE(other_row, LW_NAME(panel), other_row->get_index() % 2 ? theme_cache.odd_style : theme_cache.even_style);
|
||||
|
||||
drag_index += drag_dir;
|
||||
}
|
||||
}
|
||||
|
||||
void BlackboardPlanEditor::_visibility_changed() {
|
||||
if (!is_visible() && plan.is_valid()) {
|
||||
plan->notify_property_list_changed();
|
||||
}
|
||||
}
|
||||
|
||||
void BlackboardPlanEditor::_refresh() {
|
||||
for (int i = 0; i < rows_vbox->get_child_count(); i++) {
|
||||
Control *child = Object::cast_to<Control>(rows_vbox->get_child(i));
|
||||
ERR_FAIL_NULL(child);
|
||||
child->hide();
|
||||
child->queue_free();
|
||||
}
|
||||
|
||||
// TODO: Name validation
|
||||
|
||||
PackedStringArray names = plan->list_vars();
|
||||
int idx = 0;
|
||||
for (const String &var_name : names) {
|
||||
BBVariable var = plan->get_var(var_name);
|
||||
|
||||
PanelContainer *row_panel = memnew(PanelContainer);
|
||||
rows_vbox->add_child(row_panel);
|
||||
ADD_STYLEBOX_OVERRIDE(row_panel, LW_NAME(panel), idx % 2 ? theme_cache.odd_style : theme_cache.even_style);
|
||||
row_panel->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
|
||||
HBoxContainer *props_hbox = memnew(HBoxContainer);
|
||||
row_panel->add_child(props_hbox);
|
||||
props_hbox->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
|
||||
Button *drag_button = memnew(Button);
|
||||
props_hbox->add_child(drag_button);
|
||||
drag_button->set_custom_minimum_size(Size2(28.0, 28.0) * EDSCALE);
|
||||
BUTTON_SET_ICON(drag_button, theme_cache.grab_icon);
|
||||
drag_button->connect(LW_NAME(gui_input), callable_mp(this, &BlackboardPlanEditor::_drag_button_gui_input));
|
||||
drag_button->connect(LW_NAME(button_down), callable_mp(this, &BlackboardPlanEditor::_drag_button_down).bind(row_panel));
|
||||
drag_button->connect(LW_NAME(button_up), callable_mp(this, &BlackboardPlanEditor::_drag_button_up));
|
||||
|
||||
LineEdit *name_edit = memnew(LineEdit);
|
||||
props_hbox->add_child(name_edit);
|
||||
name_edit->set_text(var_name);
|
||||
name_edit->set_placeholder(TTR("Variable name"));
|
||||
name_edit->set_flat(true);
|
||||
name_edit->set_custom_minimum_size(Size2(300.0, 0.0) * EDSCALE);
|
||||
name_edit->connect(LW_NAME(text_changed), callable_mp(this, &BlackboardPlanEditor::_rename_var).bind(idx));
|
||||
name_edit->connect(LW_NAME(text_submitted), callable_mp(this, &BlackboardPlanEditor::_refresh).unbind(1));
|
||||
|
||||
Button *type_choice = memnew(Button);
|
||||
props_hbox->add_child(type_choice);
|
||||
type_choice->set_custom_minimum_size(Size2(170, 0.0) * EDSCALE);
|
||||
type_choice->set_text(Variant::get_type_name(var.get_type()));
|
||||
type_choice->set_tooltip_text(Variant::get_type_name(var.get_type()));
|
||||
BUTTON_SET_ICON(type_choice, get_theme_icon(Variant::get_type_name(var.get_type()), LW_NAME(EditorIcons)));
|
||||
type_choice->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
|
||||
type_choice->set_flat(true);
|
||||
type_choice->set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT);
|
||||
type_choice->connect(LW_NAME(pressed), callable_mp(this, &BlackboardPlanEditor::_show_button_popup).bind(type_choice, type_menu, idx));
|
||||
|
||||
Button *hint_choice = memnew(Button);
|
||||
props_hbox->add_child(hint_choice);
|
||||
hint_choice->set_custom_minimum_size(Size2(150.0, 0.0) * EDSCALE);
|
||||
hint_choice->set_text(LimboUtility::get_singleton()->get_property_hint_text(var.get_hint()));
|
||||
hint_choice->set_tooltip_text(LimboUtility::get_singleton()->get_property_hint_text(var.get_hint()));
|
||||
hint_choice->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
|
||||
hint_choice->set_flat(true);
|
||||
hint_choice->set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT);
|
||||
hint_choice->connect(LW_NAME(pressed), callable_mp(this, &BlackboardPlanEditor::_show_button_popup).bind(hint_choice, hint_menu, idx));
|
||||
|
||||
LineEdit *hint_string_edit = memnew(LineEdit);
|
||||
props_hbox->add_child(hint_string_edit);
|
||||
hint_string_edit->set_custom_minimum_size(Size2(300.0, 0.0) * EDSCALE);
|
||||
hint_string_edit->set_text(var.get_hint_string());
|
||||
hint_string_edit->set_placeholder(TTR("Hint string"));
|
||||
hint_string_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
hint_string_edit->set_flat(true);
|
||||
hint_string_edit->connect(LW_NAME(text_changed), callable_mp(this, &BlackboardPlanEditor::_change_var_hint_string).bind(idx));
|
||||
hint_string_edit->connect(LW_NAME(text_submitted), callable_mp(this, &BlackboardPlanEditor::_refresh).unbind(1));
|
||||
|
||||
Button *trash_button = memnew(Button);
|
||||
props_hbox->add_child(trash_button);
|
||||
trash_button->set_custom_minimum_size(Size2(24.0, 0.0) * EDSCALE);
|
||||
BUTTON_SET_ICON(trash_button, theme_cache.trash_icon);
|
||||
trash_button->connect(LW_NAME(pressed), callable_mp(this, &BlackboardPlanEditor::_trash_var).bind(idx));
|
||||
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void BlackboardPlanEditor::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
theme_cache.trash_icon = get_theme_icon(LW_NAME(Remove), LW_NAME(EditorIcons));
|
||||
theme_cache.grab_icon = get_theme_icon(LW_NAME(TripleBar), LW_NAME(EditorIcons));
|
||||
|
||||
BUTTON_SET_ICON(add_var_tool, get_theme_icon(LW_NAME(Add), LW_NAME(EditorIcons)));
|
||||
|
||||
type_menu->clear();
|
||||
for (int i = 0; i < Variant::VARIANT_MAX; i++) {
|
||||
if (i == Variant::RID || i == Variant::CALLABLE || i == Variant::SIGNAL) {
|
||||
continue;
|
||||
}
|
||||
String type = Variant::get_type_name(Variant::Type(i));
|
||||
type_menu->add_icon_item(get_theme_icon(type, LW_NAME(EditorIcons)), type, i);
|
||||
}
|
||||
|
||||
ADD_STYLEBOX_OVERRIDE(scroll_container, LW_NAME(panel), get_theme_stylebox(LW_NAME(panel), LW_NAME(Tree)));
|
||||
|
||||
Color bg_color = get_theme_color(LW_NAME(dark_color_2), LW_NAME(Editor));
|
||||
theme_cache.odd_style->set_bg_color(bg_color.darkened(-0.05));
|
||||
theme_cache.even_style->set_bg_color(bg_color.darkened(0.05));
|
||||
theme_cache.header_style->set_bg_color(bg_color.darkened(-0.2));
|
||||
|
||||
ADD_STYLEBOX_OVERRIDE(header_row, LW_NAME(panel), theme_cache.header_style);
|
||||
} break;
|
||||
case NOTIFICATION_READY: {
|
||||
add_var_tool->connect(LW_NAME(pressed), callable_mp(this, &BlackboardPlanEditor::_add_var));
|
||||
connect(LW_NAME(visibility_changed), callable_mp(this, &BlackboardPlanEditor::_visibility_changed));
|
||||
type_menu->connect(LW_NAME(id_pressed), callable_mp(this, &BlackboardPlanEditor::_type_chosen));
|
||||
hint_menu->connect(LW_NAME(id_pressed), callable_mp(this, &BlackboardPlanEditor::_hint_chosen));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
BlackboardPlanEditor::BlackboardPlanEditor() {
|
||||
set_title(TTR("Manage Blackboard Plan"));
|
||||
|
||||
VBoxContainer *vbox = memnew(VBoxContainer);
|
||||
vbox->add_theme_constant_override(LW_NAME(separation), 8 * EDSCALE);
|
||||
add_child(vbox);
|
||||
|
||||
HBoxContainer *toolbar = memnew(HBoxContainer);
|
||||
vbox->add_child(toolbar);
|
||||
|
||||
add_var_tool = memnew(Button);
|
||||
toolbar->add_child(add_var_tool);
|
||||
add_var_tool->set_focus_mode(Control::FOCUS_NONE);
|
||||
add_var_tool->set_text(TTR("Add variable"));
|
||||
|
||||
{
|
||||
// * Header
|
||||
header_row = memnew(PanelContainer);
|
||||
vbox->add_child(header_row);
|
||||
header_row->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
|
||||
HBoxContainer *labels_hbox = memnew(HBoxContainer);
|
||||
header_row->add_child(labels_hbox);
|
||||
labels_hbox->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
|
||||
Control *offset = memnew(Control);
|
||||
labels_hbox->add_child(offset);
|
||||
offset->set_custom_minimum_size(Size2(2.0, 0.0) * EDSCALE);
|
||||
|
||||
Label *drag_header = memnew(Label);
|
||||
labels_hbox->add_child(drag_header);
|
||||
drag_header->set_custom_minimum_size(Size2(28.0, 28.0) * EDSCALE);
|
||||
|
||||
Label *name_header = memnew(Label);
|
||||
labels_hbox->add_child(name_header);
|
||||
name_header->set_text(TTR("Name"));
|
||||
name_header->set_custom_minimum_size(Size2(300.0, 0.0) * EDSCALE);
|
||||
name_header->set_theme_type_variation(LW_NAME(HeaderSmall));
|
||||
|
||||
Label *type_header = memnew(Label);
|
||||
labels_hbox->add_child(type_header);
|
||||
type_header->set_text(TTR("Type"));
|
||||
type_header->set_custom_minimum_size(Size2(170, 0.0) * EDSCALE);
|
||||
type_header->set_theme_type_variation(LW_NAME(HeaderSmall));
|
||||
|
||||
Label *hint_header = memnew(Label);
|
||||
labels_hbox->add_child(hint_header);
|
||||
hint_header->set_text(TTR("Hint"));
|
||||
hint_header->set_custom_minimum_size(Size2(150.0, 0.0) * EDSCALE);
|
||||
hint_header->set_theme_type_variation(LW_NAME(HeaderSmall));
|
||||
|
||||
Label *hint_string_header = memnew(Label);
|
||||
labels_hbox->add_child(hint_string_header);
|
||||
hint_string_header->set_text(TTR("Hint string"));
|
||||
hint_string_header->set_custom_minimum_size(Size2(300.0, 0.0) * EDSCALE);
|
||||
hint_string_header->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
hint_string_header->set_theme_type_variation(LW_NAME(HeaderSmall));
|
||||
}
|
||||
|
||||
scroll_container = memnew(ScrollContainer);
|
||||
vbox->add_child(scroll_container);
|
||||
scroll_container->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
scroll_container->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
scroll_container->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
|
||||
scroll_container->set_custom_minimum_size(Size2(0.0, 600.0) * EDSCALE);
|
||||
|
||||
rows_vbox = memnew(VBoxContainer);
|
||||
scroll_container->add_child(rows_vbox);
|
||||
rows_vbox->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
rows_vbox->add_theme_constant_override(LW_NAME(separation), 0);
|
||||
|
||||
type_menu = memnew(PopupMenu);
|
||||
add_child(type_menu);
|
||||
|
||||
hint_menu = memnew(PopupMenu);
|
||||
add_child(hint_menu);
|
||||
for (int i = 0; i < PropertyHint::PROPERTY_HINT_MAX; i++) {
|
||||
hint_menu->add_item(LimboUtility::get_singleton()->get_property_hint_text(PropertyHint(i)), i);
|
||||
}
|
||||
|
||||
theme_cache.odd_style.instantiate();
|
||||
theme_cache.even_style.instantiate();
|
||||
theme_cache.header_style.instantiate();
|
||||
}
|
||||
|
||||
// ***** EditorInspectorPluginBBPlan *****
|
||||
|
||||
void EditorInspectorPluginBBPlan::_edit_plan(const Ref<BlackboardPlan> &p_plan) {
|
||||
ERR_FAIL_NULL(p_plan);
|
||||
plan_editor->edit_plan(p_plan);
|
||||
plan_editor->popup_centered();
|
||||
}
|
||||
|
||||
void EditorInspectorPluginBBPlan::_open_base_plan(const Ref<BlackboardPlan> &p_plan) {
|
||||
ERR_FAIL_NULL(p_plan);
|
||||
ERR_FAIL_NULL(p_plan->get_base_plan());
|
||||
EditorInterface::get_singleton()->call_deferred("edit_resource", p_plan->get_base_plan());
|
||||
}
|
||||
|
||||
#ifdef LIMBOAI_MODULE
|
||||
bool EditorInspectorPluginBBPlan::can_handle(Object *p_object) {
|
||||
#elif LIMBOAI_GDEXTENSION
|
||||
bool EditorInspectorPluginBBPlan::_can_handle(Object *p_object) const {
|
||||
#endif
|
||||
Ref<BlackboardPlan> plan = Object::cast_to<BlackboardPlan>(p_object);
|
||||
if (plan.is_valid()) {
|
||||
plan->sync_with_base_plan();
|
||||
}
|
||||
return plan.is_valid();
|
||||
}
|
||||
|
||||
#ifdef LIMBOAI_MODULE
|
||||
void EditorInspectorPluginBBPlan::parse_begin(Object *p_object) {
|
||||
#elif LIMBOAI_GDEXTENSION
|
||||
void EditorInspectorPluginBBPlan::_parse_begin(Object *p_object) {
|
||||
#endif
|
||||
Ref<BlackboardPlan> plan = Object::cast_to<BlackboardPlan>(p_object);
|
||||
ERR_FAIL_NULL(plan);
|
||||
|
||||
PanelContainer *panel = memnew(PanelContainer);
|
||||
ADD_STYLEBOX_OVERRIDE(panel, LW_NAME(panel), toolbar_style);
|
||||
|
||||
MarginContainer *margin_container = memnew(MarginContainer);
|
||||
panel->add_child(margin_container);
|
||||
margin_container->set_theme_type_variation("MarginContainer4px");
|
||||
margin_container->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
margin_container->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
|
||||
VBoxContainer *toolbar = memnew(VBoxContainer);
|
||||
margin_container->add_child(toolbar);
|
||||
toolbar->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
|
||||
if (plan->is_derived()) {
|
||||
Button *goto_btn = memnew(Button);
|
||||
toolbar->add_child(goto_btn);
|
||||
goto_btn->set_text(TTR("Edit Base"));
|
||||
goto_btn->set_h_size_flags(Control::SIZE_SHRINK_CENTER);
|
||||
goto_btn->set_custom_minimum_size(Size2(150.0, 0.0) * EDSCALE);
|
||||
BUTTON_SET_ICON(goto_btn, EditorInterface::get_singleton()->get_editor_theme()->get_icon(LW_NAME(Edit), LW_NAME(EditorIcons)));
|
||||
goto_btn->connect(LW_NAME(pressed), callable_mp(this, &EditorInspectorPluginBBPlan::_open_base_plan).bind(plan));
|
||||
} else {
|
||||
Button *edit_btn = memnew(Button);
|
||||
toolbar->add_child(edit_btn);
|
||||
edit_btn->set_text(TTR("Manage..."));
|
||||
edit_btn->set_h_size_flags(Control::SIZE_SHRINK_CENTER);
|
||||
edit_btn->set_custom_minimum_size(Size2(150.0, 0.0) * EDSCALE);
|
||||
BUTTON_SET_ICON(edit_btn, EditorInterface::get_singleton()->get_editor_theme()->get_icon(LW_NAME(EditAddRemove), LW_NAME(EditorIcons)));
|
||||
edit_btn->connect(LW_NAME(pressed), callable_mp(this, &EditorInspectorPluginBBPlan::_edit_plan).bind(plan));
|
||||
}
|
||||
|
||||
add_custom_control(panel);
|
||||
}
|
||||
|
||||
EditorInspectorPluginBBPlan::EditorInspectorPluginBBPlan() {
|
||||
plan_editor = memnew(BlackboardPlanEditor);
|
||||
EditorInterface::get_singleton()->get_base_control()->add_child(plan_editor);
|
||||
plan_editor->hide();
|
||||
|
||||
toolbar_style = Ref<StyleBoxFlat>(memnew(StyleBoxFlat));
|
||||
Color bg = EditorInterface::get_singleton()->get_editor_theme()->get_color(LW_NAME(accent_color), LW_NAME(Editor));
|
||||
bg = bg.darkened(-0.1);
|
||||
bg.a *= 0.2;
|
||||
toolbar_style->set_bg_color(bg);
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/**
|
||||
* blackboard_plan_editor.h
|
||||
* =============================================================================
|
||||
* Copyright 2021-2024 Serhii Snitsaruk
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
#ifndef BLACKBOARD_PLAN_EDITOR_H
|
||||
#define BLACKBOARD_PLAN_EDITOR_H
|
||||
|
||||
#include "../blackboard/blackboard_plan.h"
|
||||
|
||||
#ifdef LIMBOAI_MODULE
|
||||
#include "editor/editor_inspector.h"
|
||||
#include "scene/gui/dialogs.h"
|
||||
#endif // LIMBOAI_MODULE
|
||||
|
||||
#ifdef LIMBOAI_GDEXTENSION
|
||||
#include <godot_cpp/classes/accept_dialog.hpp>
|
||||
#include <godot_cpp/classes/editor_inspector_plugin.hpp>
|
||||
#include <godot_cpp/classes/panel_container.hpp>
|
||||
#include <godot_cpp/classes/popup_menu.hpp>
|
||||
#include <godot_cpp/classes/scroll_container.hpp>
|
||||
#include <godot_cpp/classes/style_box_flat.hpp>
|
||||
#include <godot_cpp/classes/v_box_container.hpp>
|
||||
using namespace godot;
|
||||
#endif // LIMBOAI_GDEXTENSION
|
||||
|
||||
// *****
|
||||
|
||||
class BlackboardPlanEditor : public AcceptDialog {
|
||||
GDCLASS(BlackboardPlanEditor, AcceptDialog);
|
||||
|
||||
private:
|
||||
struct ThemeCache {
|
||||
Ref<Texture2D> trash_icon;
|
||||
Ref<Texture2D> grab_icon;
|
||||
Ref<StyleBoxFlat> odd_style;
|
||||
Ref<StyleBoxFlat> even_style;
|
||||
Ref<StyleBoxFlat> header_style;
|
||||
} theme_cache;
|
||||
|
||||
int last_index = 0;
|
||||
int drag_mouse_y_delta = 0;
|
||||
int drag_start = -1;
|
||||
int drag_index = -1;
|
||||
|
||||
Ref<BlackboardPlan> plan;
|
||||
|
||||
VBoxContainer *rows_vbox;
|
||||
Button *add_var_tool;
|
||||
PanelContainer *header_row;
|
||||
ScrollContainer *scroll_container;
|
||||
PopupMenu *type_menu;
|
||||
PopupMenu *hint_menu;
|
||||
|
||||
void _add_var();
|
||||
void _trash_var(int p_index);
|
||||
void _rename_var(const String &p_new_name, int p_index);
|
||||
void _change_var_type(Variant::Type p_new_type, int p_index);
|
||||
void _change_var_hint(PropertyHint p_new_hint, int p_index);
|
||||
void _change_var_hint_string(const String &p_new_hint_string, int p_index);
|
||||
|
||||
void _show_button_popup(Button *p_button, PopupMenu *p_popup, int p_index);
|
||||
void _type_chosen(int id);
|
||||
void _hint_chosen(int id);
|
||||
|
||||
void _drag_button_down(Control *p_row);
|
||||
void _drag_button_up();
|
||||
void _drag_button_gui_input(const Ref<InputEvent> &p_event);
|
||||
|
||||
void _refresh();
|
||||
void _visibility_changed();
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
void edit_plan(const Ref<BlackboardPlan> &p_plan);
|
||||
|
||||
BlackboardPlanEditor();
|
||||
};
|
||||
|
||||
// *****
|
||||
|
||||
class EditorInspectorPluginBBPlan : public EditorInspectorPlugin {
|
||||
GDCLASS(EditorInspectorPluginBBPlan, EditorInspectorPlugin);
|
||||
|
||||
private:
|
||||
BlackboardPlanEditor *plan_editor;
|
||||
Ref<StyleBoxFlat> toolbar_style;
|
||||
|
||||
void _edit_plan(const Ref<BlackboardPlan> &p_plan);
|
||||
void _open_base_plan(const Ref<BlackboardPlan> &p_plan);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
public:
|
||||
#ifdef LIMBOAI_MODULE
|
||||
virtual bool can_handle(Object *p_object) override;
|
||||
virtual void parse_begin(Object *p_object) override;
|
||||
#elif LIMBOAI_GDEXTENSION
|
||||
virtual bool _can_handle(Object *p_object) const override;
|
||||
virtual void _parse_begin(Object *p_object) override;
|
||||
#endif
|
||||
|
||||
EditorInspectorPluginBBPlan();
|
||||
};
|
||||
|
||||
#endif // BLACKBOARD_PLAN_EDITOR_H
|
|
@ -18,11 +18,12 @@
|
|||
#include "../bt/tasks/composites/bt_probability_selector.h"
|
||||
#include "../bt/tasks/composites/bt_selector.h"
|
||||
#include "../bt/tasks/decorators/bt_subtree.h"
|
||||
#include "../editor/debugger/limbo_debugger_plugin.h"
|
||||
#include "../editor/editor_property_bb_param.h"
|
||||
#include "../util/limbo_compat.h"
|
||||
#include "../util/limbo_utility.h"
|
||||
#include "action_banner.h"
|
||||
#include "blackboard_plan_editor.h"
|
||||
#include "debugger/limbo_debugger_plugin.h"
|
||||
#include "editor_property_bb_param.h"
|
||||
|
||||
#ifdef LIMBOAI_MODULE
|
||||
#include "core/config/project_settings.h"
|
||||
|
@ -183,8 +184,9 @@ void LimboAIEditor::_update_history_buttons() {
|
|||
}
|
||||
|
||||
void LimboAIEditor::_new_bt() {
|
||||
BehaviorTree *bt = memnew(BehaviorTree);
|
||||
Ref<BehaviorTree> bt = memnew(BehaviorTree);
|
||||
bt->set_root_task(memnew(BTSelector));
|
||||
bt->set_blackboard_plan(memnew(BlackboardPlan));
|
||||
EDIT_RESOURCE(bt);
|
||||
}
|
||||
|
||||
|
@ -221,6 +223,11 @@ void LimboAIEditor::edit_bt(Ref<BehaviorTree> p_behavior_tree, bool p_force_refr
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef LIMBOAI_MODULE
|
||||
p_behavior_tree->editor_set_section_unfold("blackboard_plan", true);
|
||||
p_behavior_tree->notify_property_list_changed();
|
||||
#endif // LIMBOAI_MODULE
|
||||
|
||||
task_tree->load_bt(p_behavior_tree);
|
||||
|
||||
int idx = history.find(p_behavior_tree);
|
||||
|
@ -697,6 +704,9 @@ void LimboAIEditor::_on_visibility_changed() {
|
|||
void LimboAIEditor::_on_header_pressed() {
|
||||
_update_header();
|
||||
task_tree->deselect();
|
||||
#ifdef LIMBOAI_MODULE
|
||||
task_tree->get_bt()->editor_set_section_unfold("blackboard_plan", true);
|
||||
#endif // LIMBOAI_MODULE
|
||||
EDIT_RESOURCE(task_tree->get_bt());
|
||||
}
|
||||
|
||||
|
@ -1393,6 +1403,11 @@ void LimboAIEditorPlugin::_notification(int p_notification) {
|
|||
switch (p_notification) {
|
||||
case NOTIFICATION_READY: {
|
||||
add_debugger_plugin(memnew(LimboDebuggerPlugin));
|
||||
add_inspector_plugin(memnew(EditorInspectorPluginBBPlan));
|
||||
#ifdef LIMBOAI_MODULE
|
||||
// ! Only used in the module version.
|
||||
add_inspector_plugin(memnew(EditorInspectorPluginBBParam));
|
||||
#endif // LIMBOAI_MODULE
|
||||
} break;
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
// Add BehaviorTree to the list of resources that should open in a new inspector.
|
||||
|
@ -1446,11 +1461,6 @@ LimboAIEditorPlugin::LimboAIEditorPlugin() {
|
|||
MAIN_SCREEN_CONTROL()->add_child(limbo_ai_editor);
|
||||
limbo_ai_editor->hide();
|
||||
limbo_ai_editor->set_plugin(this);
|
||||
|
||||
#ifdef LIMBOAI_MODULE
|
||||
// ! Only used in the module version.
|
||||
add_inspector_plugin(memnew(EditorInspectorPluginBBParam));
|
||||
#endif // LIMBOAI_MODULE
|
||||
}
|
||||
|
||||
LimboAIEditorPlugin::~LimboAIEditorPlugin() {
|
||||
|
|
|
@ -190,7 +190,7 @@ bool LimboHSM::dispatch(const String &p_event, const Variant &p_cargo) {
|
|||
void LimboHSM::initialize(Node *p_agent, const Ref<Blackboard> &p_parent_scope) {
|
||||
ERR_FAIL_COND(p_agent == nullptr);
|
||||
if (!p_parent_scope.is_null()) {
|
||||
blackboard->set_parent_scope(p_parent_scope);
|
||||
blackboard->set_parent(p_parent_scope);
|
||||
}
|
||||
_initialize(p_agent, nullptr);
|
||||
|
||||
|
|
|
@ -69,8 +69,9 @@ void LimboState::_initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard)
|
|||
agent = p_agent;
|
||||
|
||||
if (!p_blackboard.is_null()) {
|
||||
if (!blackboard->get_data().is_empty()) {
|
||||
blackboard->set_parent_scope(p_blackboard);
|
||||
if (blackboard_plan.is_valid() && !blackboard_plan->is_empty()) {
|
||||
blackboard = blackboard_plan->create_blackboard();
|
||||
blackboard->set_parent(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_plan", "p_plan"), &LimboState::set_blackboard_plan);
|
||||
ClassDB::bind_method(D_METHOD("get_blackboard_plan"), &LimboState::get_blackboard_plan);
|
||||
|
||||
#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_plan", PROPERTY_HINT_RESOURCE_TYPE, "BlackboardPlan", PROPERTY_USAGE_DEFAULT), "set_blackboard_plan", "get_blackboard_plan");
|
||||
|
||||
ADD_SIGNAL(MethodInfo("setup"));
|
||||
ADD_SIGNAL(MethodInfo("entered"));
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define LIMBO_STATE_H
|
||||
|
||||
#include "../blackboard/blackboard.h"
|
||||
#include "../blackboard/blackboard_plan.h"
|
||||
|
||||
#include "../util/limbo_string_names.h"
|
||||
|
||||
|
@ -37,6 +38,7 @@ class LimboState : public Node {
|
|||
GDCLASS(LimboState, Node);
|
||||
|
||||
private:
|
||||
Ref<BlackboardPlan> blackboard_plan;
|
||||
Node *agent;
|
||||
Ref<Blackboard> blackboard;
|
||||
HashMap<String, Callable> 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<Blackboard> &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_plan(const Ref<BlackboardPlan> p_plan) { blackboard_plan = p_plan; }
|
||||
Ref<BlackboardPlan> get_blackboard_plan() const { return blackboard_plan; }
|
||||
|
||||
Ref<Blackboard> get_blackboard() const { return blackboard; }
|
||||
|
||||
Node *get_agent() const { return agent; }
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0h16v16h-16z" fill="none"/><path d="m13 3h1.439c.861 0 1.56.699 1.56 1.56v8.88c0 .861-.699 1.56-1.56 1.56h-12.877c-.828 0-1.507-.647-1.558-1.463-.001.009-.001.017-.002.026-.001-.002 0-.049-.001-.119v-.004c0-.234.001-.591.001-.712v-8.168-1.468c0-1.295 2.999-1.483 2.999-.892v.8h3.999v1h-3.999v9.058c0-.362-1.126-.555-1.999-.35v.732c0 .309.251.56.56.56h12.877c.309 0 .56-.251.56-.56v-8.88c0-.309-.251-.56-.56-.56h-1.439zm-5 7v-6h4v6l-2 2zm2-5h-1v4h1zm-2-3.204c0-.439.896-.796 2-.796s2 .357 2 .796v1.204h-4z" fill="#c38ef1"/></svg>
|
After Width: | Height: | Size: 686 B |
|
@ -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_plan.h"
|
||||
#include "bt/behavior_tree.h"
|
||||
#include "bt/bt_player.h"
|
||||
#include "bt/bt_state.h"
|
||||
|
@ -94,6 +95,7 @@
|
|||
#include "bt/tasks/utility/bt_wait.h"
|
||||
#include "bt/tasks/utility/bt_wait_ticks.h"
|
||||
#include "editor/action_banner.h"
|
||||
#include "editor/blackboard_plan_editor.h"
|
||||
#include "editor/debugger/behavior_tree_data.h"
|
||||
#include "editor/debugger/limbo_debugger.h"
|
||||
#include "editor/debugger/limbo_debugger_plugin.h"
|
||||
|
@ -133,6 +135,7 @@ void initialize_limboai_module(ModuleInitializationLevel p_level) {
|
|||
|
||||
GDREGISTER_CLASS(LimboUtility);
|
||||
GDREGISTER_CLASS(Blackboard);
|
||||
GDREGISTER_CLASS(BlackboardPlan);
|
||||
|
||||
GDREGISTER_CLASS(LimboState);
|
||||
GDREGISTER_CLASS(LimboHSM);
|
||||
|
@ -251,6 +254,8 @@ void initialize_limboai_module(ModuleInitializationLevel p_level) {
|
|||
GDREGISTER_CLASS(BehaviorTreeView);
|
||||
GDREGISTER_CLASS(LimboDebuggerTab);
|
||||
GDREGISTER_CLASS(LimboDebuggerPlugin);
|
||||
GDREGISTER_CLASS(BlackboardPlanEditor);
|
||||
GDREGISTER_CLASS(EditorInspectorPluginBBPlan);
|
||||
GDREGISTER_CLASS(LimboAIEditor);
|
||||
GDREGISTER_CLASS(LimboAIEditorPlugin);
|
||||
#endif // LIMBOAI_GDEXTENSION
|
||||
|
|
|
@ -50,7 +50,7 @@ TEST_CASE("[Modules][LimboAI] BTNewScope") {
|
|||
CHECK(ns->get_blackboard() != parent->get_blackboard());
|
||||
CHECK(ns->get_blackboard() == child->get_blackboard());
|
||||
CHECK(parent->get_blackboard() == parent_bb);
|
||||
CHECK(ns->get_blackboard()->get_parent_scope() == parent_bb);
|
||||
CHECK(ns->get_blackboard()->get_parent() == parent_bb);
|
||||
|
||||
ns->get_blackboard()->set_var("fruit", "pear"); // * override "fruit"
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#define DIR_ACCESS_CREATE() DirAccess::create(DirAccess::ACCESS_RESOURCES)
|
||||
#define PERFORMANCE_ADD_CUSTOM_MONITOR(m_id, m_callable) (Performance::get_singleton()->add_custom_monitor(m_id, m_callable, Variant()))
|
||||
#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 VARIANT_EVALUATE(m_op, m_lvalue, m_rvalue, r_ret) r_ret = Variant::evaluate(m_op, m_lvalue, m_rvalue)
|
||||
|
||||
|
@ -130,6 +131,7 @@ using namespace godot;
|
|||
#define DIR_ACCESS_CREATE() DirAccess::open("res://")
|
||||
#define PERFORMANCE_ADD_CUSTOM_MONITOR(m_id, m_callable) (Performance::get_singleton()->add_custom_monitor(m_id, m_callable))
|
||||
#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 VARIANT_EVALUATE(m_op, m_lvalue, m_rvalue, r_ret) \
|
||||
{ \
|
||||
|
@ -218,6 +220,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)
|
||||
|
|
|
@ -42,6 +42,7 @@ LimboStringNames::LimboStringNames() {
|
|||
_update_banners = SN("_update_banners");
|
||||
_weight_ = SN("_weight_");
|
||||
accent_color = SN("accent_color");
|
||||
Add = SN("Add");
|
||||
add_child = SN("add_child");
|
||||
add_child_at_index = SN("add_child_at_index");
|
||||
AnimationFilter = SN("AnimationFilter");
|
||||
|
@ -52,13 +53,19 @@ LimboStringNames::LimboStringNames() {
|
|||
bold = SN("bold");
|
||||
BTAlwaysFail = SN("BTAlwaysFail");
|
||||
BTAlwaysSucceed = SN("BTAlwaysSucceed");
|
||||
button_down = SN("button_down");
|
||||
button_up = SN("button_up");
|
||||
changed = SN("changed");
|
||||
connect = SN("connect");
|
||||
dark_color_1 = SN("dark_color_1");
|
||||
dark_color_2 = SN("dark_color_2");
|
||||
Debug = SN("Debug");
|
||||
disabled_font_color = SN("disabled_font_color");
|
||||
doc_italic = SN("doc_italic");
|
||||
draw = SN("draw");
|
||||
Duplicate = SN("Duplicate");
|
||||
Edit = SN("Edit");
|
||||
EditAddRemove = SN("EditAddRemove");
|
||||
Editor = SN("Editor");
|
||||
EditorFonts = SN("EditorFonts");
|
||||
EditorIcons = SN("EditorIcons");
|
||||
|
@ -76,6 +83,7 @@ LimboStringNames::LimboStringNames() {
|
|||
gui_input = SN("gui_input");
|
||||
GuiTreeArrowDown = SN("GuiTreeArrowDown");
|
||||
GuiTreeArrowRight = SN("GuiTreeArrowRight");
|
||||
HeaderSmall = SN("HeaderSmall");
|
||||
Help = SN("Help");
|
||||
icon_max_width = SN("icon_max_width");
|
||||
id_pressed = SN("id_pressed");
|
||||
|
@ -97,6 +105,7 @@ LimboStringNames::LimboStringNames() {
|
|||
NodeWarning = SN("NodeWarning");
|
||||
NonFavorite = SN("NonFavorite");
|
||||
normal = SN("normal");
|
||||
panel = SN("panel");
|
||||
popup_hide = SN("popup_hide");
|
||||
pressed = SN("pressed");
|
||||
probability_clicked = SN("probability_clicked");
|
||||
|
@ -111,6 +120,7 @@ LimboStringNames::LimboStringNames() {
|
|||
Script = SN("Script");
|
||||
ScriptCreate = SN("ScriptCreate");
|
||||
Search = SN("Search");
|
||||
separation = SN("separation");
|
||||
set_custom_name = SN("set_custom_name");
|
||||
set_root_task = SN("set_root_task");
|
||||
setup = SN("setup");
|
||||
|
@ -125,9 +135,12 @@ LimboStringNames::LimboStringNames() {
|
|||
task_meta = SN("task_meta");
|
||||
task_selected = SN("task_selected");
|
||||
text_changed = SN("text_changed");
|
||||
text_submitted = SN("text_submitted");
|
||||
timeout = SN("timeout");
|
||||
toggled = SN("toggled");
|
||||
Tools = SN("Tools");
|
||||
Tree = SN("Tree");
|
||||
TripleBar = SN("TripleBar");
|
||||
update_task = SN("update_task");
|
||||
update_tree = SN("update_tree");
|
||||
updated = SN("updated");
|
||||
|
|
|
@ -58,6 +58,7 @@ public:
|
|||
StringName accent_color;
|
||||
StringName add_child_at_index;
|
||||
StringName add_child;
|
||||
StringName Add;
|
||||
StringName AnimationFilter;
|
||||
StringName Back;
|
||||
StringName behavior_tree_finished;
|
||||
|
@ -66,13 +67,19 @@ public:
|
|||
StringName bold;
|
||||
StringName BTAlwaysFail;
|
||||
StringName BTAlwaysSucceed;
|
||||
StringName button_down;
|
||||
StringName button_up;
|
||||
StringName changed;
|
||||
StringName connect;
|
||||
StringName dark_color_1;
|
||||
StringName dark_color_2;
|
||||
StringName Debug;
|
||||
StringName disabled_font_color;
|
||||
StringName doc_italic;
|
||||
StringName draw;
|
||||
StringName Duplicate;
|
||||
StringName Edit;
|
||||
StringName EditAddRemove;
|
||||
StringName Editor;
|
||||
StringName EditorFonts;
|
||||
StringName EditorIcons;
|
||||
|
@ -90,6 +97,7 @@ public:
|
|||
StringName gui_input;
|
||||
StringName GuiTreeArrowDown;
|
||||
StringName GuiTreeArrowRight;
|
||||
StringName HeaderSmall;
|
||||
StringName Help;
|
||||
StringName icon_max_width;
|
||||
StringName id_pressed;
|
||||
|
@ -112,6 +120,7 @@ public:
|
|||
StringName NodeWarning;
|
||||
StringName NonFavorite;
|
||||
StringName normal;
|
||||
StringName panel;
|
||||
StringName popup_hide;
|
||||
StringName pressed;
|
||||
StringName probability_clicked;
|
||||
|
@ -126,6 +135,7 @@ public:
|
|||
StringName Script;
|
||||
StringName ScriptCreate;
|
||||
StringName Search;
|
||||
StringName separation;
|
||||
StringName set_custom_name;
|
||||
StringName set_root_task;
|
||||
StringName setup;
|
||||
|
@ -140,9 +150,12 @@ public:
|
|||
StringName task_meta;
|
||||
StringName task_selected;
|
||||
StringName text_changed;
|
||||
StringName text_submitted;
|
||||
StringName timeout;
|
||||
StringName toggled;
|
||||
StringName Tools;
|
||||
StringName Tree;
|
||||
StringName TripleBar;
|
||||
StringName update_task;
|
||||
StringName update_tree;
|
||||
StringName updated;
|
||||
|
|
|
@ -288,6 +288,129 @@ Variant LimboUtility::perform_operation(Operation p_operation, const Variant &le
|
|||
return ret;
|
||||
}
|
||||
|
||||
String LimboUtility::get_property_hint_text(PropertyHint p_hint) const {
|
||||
switch (p_hint) {
|
||||
case PROPERTY_HINT_NONE: {
|
||||
return "NONE";
|
||||
}
|
||||
case PROPERTY_HINT_RANGE: {
|
||||
return "RANGE";
|
||||
}
|
||||
case PROPERTY_HINT_ENUM: {
|
||||
return "ENUM";
|
||||
}
|
||||
case PROPERTY_HINT_ENUM_SUGGESTION: {
|
||||
return "SUGGESTION";
|
||||
}
|
||||
case PROPERTY_HINT_EXP_EASING: {
|
||||
return "EXP_EASING";
|
||||
}
|
||||
case PROPERTY_HINT_LINK: {
|
||||
return "LINK";
|
||||
}
|
||||
case PROPERTY_HINT_FLAGS: {
|
||||
return "FLAGS";
|
||||
}
|
||||
case PROPERTY_HINT_LAYERS_2D_RENDER: {
|
||||
return "LAYERS_2D_RENDER";
|
||||
}
|
||||
case PROPERTY_HINT_LAYERS_2D_PHYSICS: {
|
||||
return "LAYERS_2D_PHYSICS";
|
||||
}
|
||||
case PROPERTY_HINT_LAYERS_2D_NAVIGATION: {
|
||||
return "LAYERS_2D_NAVIGATION";
|
||||
}
|
||||
case PROPERTY_HINT_LAYERS_3D_RENDER: {
|
||||
return "LAYERS_3D_RENDER";
|
||||
}
|
||||
case PROPERTY_HINT_LAYERS_3D_PHYSICS: {
|
||||
return "LAYERS_3D_PHYSICS";
|
||||
}
|
||||
case PROPERTY_HINT_LAYERS_3D_NAVIGATION: {
|
||||
return "LAYERS_3D_NAVIGATION";
|
||||
}
|
||||
case PROPERTY_HINT_FILE: {
|
||||
return "FILE";
|
||||
}
|
||||
case PROPERTY_HINT_DIR: {
|
||||
return "DIR";
|
||||
}
|
||||
case PROPERTY_HINT_GLOBAL_FILE: {
|
||||
return "GLOBAL_FILE";
|
||||
}
|
||||
case PROPERTY_HINT_GLOBAL_DIR: {
|
||||
return "GLOBAL_DIR";
|
||||
}
|
||||
case PROPERTY_HINT_RESOURCE_TYPE: {
|
||||
return "RESOURCE_TYPE";
|
||||
}
|
||||
case PROPERTY_HINT_MULTILINE_TEXT: {
|
||||
return "MULTILINE_TEXT";
|
||||
}
|
||||
case PROPERTY_HINT_EXPRESSION: {
|
||||
return "EXPRESSION";
|
||||
}
|
||||
case PROPERTY_HINT_PLACEHOLDER_TEXT: {
|
||||
return "PLACEHOLDER_TEXT";
|
||||
}
|
||||
case PROPERTY_HINT_COLOR_NO_ALPHA: {
|
||||
return "COLOR_NO_ALPHA";
|
||||
}
|
||||
case PROPERTY_HINT_OBJECT_ID: {
|
||||
return "OBJECT_ID";
|
||||
}
|
||||
case PROPERTY_HINT_TYPE_STRING: {
|
||||
return "TYPE_STRING";
|
||||
}
|
||||
case PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE: {
|
||||
return "NODE_PATH_TO_EDITED_NODE";
|
||||
}
|
||||
case PROPERTY_HINT_OBJECT_TOO_BIG: {
|
||||
return "OBJECT_TOO_BIG";
|
||||
}
|
||||
case PROPERTY_HINT_NODE_PATH_VALID_TYPES: {
|
||||
return "NODE_PATH_VALID_TYPES";
|
||||
}
|
||||
case PROPERTY_HINT_SAVE_FILE: {
|
||||
return "SAVE_FILE";
|
||||
}
|
||||
case PROPERTY_HINT_GLOBAL_SAVE_FILE: {
|
||||
return "GLOBAL_SAVE_FILE";
|
||||
}
|
||||
case PROPERTY_HINT_INT_IS_OBJECTID: {
|
||||
return "INT_IS_OBJECTID";
|
||||
}
|
||||
case PROPERTY_HINT_INT_IS_POINTER: {
|
||||
return "INT_IS_POINTER";
|
||||
}
|
||||
case PROPERTY_HINT_ARRAY_TYPE: {
|
||||
return "ARRAY_TYPE";
|
||||
}
|
||||
case PROPERTY_HINT_LOCALE_ID: {
|
||||
return "LOCALE_ID";
|
||||
}
|
||||
case PROPERTY_HINT_LOCALIZABLE_STRING: {
|
||||
return "LOCALIZABLE_STRING";
|
||||
}
|
||||
case PROPERTY_HINT_NODE_TYPE: {
|
||||
return "NODE_TYPE";
|
||||
}
|
||||
case PROPERTY_HINT_HIDE_QUATERNION_EDIT: {
|
||||
return "HIDE_QUATERNION_EDIT";
|
||||
}
|
||||
case PROPERTY_HINT_PASSWORD: {
|
||||
return "PASSWORD";
|
||||
}
|
||||
case PROPERTY_HINT_LAYERS_AVOIDANCE: {
|
||||
return "LAYERS_AVOIDANCE";
|
||||
}
|
||||
case PROPERTY_HINT_MAX: {
|
||||
return "MAX";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
Ref<Shortcut> LimboUtility::add_shortcut(const String &p_path, const String &p_name, Key p_keycode) {
|
||||
|
|
|
@ -88,6 +88,8 @@ public:
|
|||
String get_operation_string(Operation p_operation) const;
|
||||
Variant perform_operation(Operation p_operation, const Variant &left_value, const Variant &right_value);
|
||||
|
||||
String get_property_hint_text(PropertyHint p_hint) const;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
Ref<Shortcut> add_shortcut(const String &p_path, const String &p_name, Key p_keycode = LW_KEY(NONE));
|
||||
bool is_shortcut(const String &p_path, const Ref<InputEvent> &p_event) const;
|
||||
|
|
Loading…
Reference in New Issue