Port the first core classes to get started

Ported: Blackboard, BTTask, BTAction, BTComment, BTDecorator, BTComposite, BTDecorator, LimboStringNames, LimboTaskDB, LimboUtility
This commit is contained in:
Serhii Snitsaruk 2024-01-06 21:04:34 +01:00
parent c18fc2abf6
commit 2c4e343a48
20 changed files with 362 additions and 56 deletions

View File

@ -11,9 +11,20 @@
#include "blackboard.h" #include "blackboard.h"
#ifdef LIMBOAI_MODULE
#include "core/error/error_macros.h" #include "core/error/error_macros.h"
#include "core/variant/variant.h" #include "core/variant/variant.h"
#include "scene/main/node.h" #include "scene/main/node.h"
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/node.hpp>
#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> Blackboard::top() const {
Ref<Blackboard> bb(this); Ref<Blackboard> bb(this);
@ -25,7 +36,7 @@ Ref<Blackboard> Blackboard::top() const {
Variant Blackboard::get_var(const Variant &p_key, const Variant &p_default) const { Variant Blackboard::get_var(const Variant &p_key, const Variant &p_default) const {
if (data.has(p_key)) { if (data.has(p_key)) {
return data.get_valid(p_key); return data.get(p_key, Variant());
} else if (parent.is_valid()) { } else if (parent.is_valid()) {
return parent->get_var(p_key, p_default); return parent->get_var(p_key, p_default);
} else { } else {

View File

@ -12,11 +12,25 @@
#ifndef BLACKBOARD_H #ifndef BLACKBOARD_H
#define BLACKBOARD_H #define BLACKBOARD_H
#ifdef LIMBOAI_MODULE
#include "core/object/object.h" #include "core/object/object.h"
#include "core/object/ref_counted.h" #include "core/object/ref_counted.h"
#include "core/variant/dictionary.h" #include "core/variant/dictionary.h"
#include "core/variant/variant.h" #include "core/variant/variant.h"
#include "scene/main/node.h" #include "scene/main/node.h"
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/node.hpp>
#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 // LIMBOAI_GDEXTENSION
class Blackboard : public RefCounted { class Blackboard : public RefCounted {
GDCLASS(Blackboard, RefCounted); GDCLASS(Blackboard, RefCounted);

View File

@ -11,7 +11,7 @@
#include "bt_action.h" #include "bt_action.h"
PackedStringArray BTAction::get_configuration_warnings() const { PackedStringArray BTAction::get_configuration_warnings() {
PackedStringArray warnings = BTTask::get_configuration_warnings(); PackedStringArray warnings = BTTask::get_configuration_warnings();
if (get_child_count_excluding_comments() != 0) { if (get_child_count_excluding_comments() != 0) {
warnings.append("Action can't have child tasks."); warnings.append("Action can't have child tasks.");

View File

@ -18,7 +18,7 @@ class BTAction : public BTTask {
GDCLASS(BTAction, BTTask); GDCLASS(BTAction, BTTask);
public: public:
virtual PackedStringArray get_configuration_warnings() const override; virtual PackedStringArray get_configuration_warnings() override;
}; };
#endif // BT_ACTION_H #endif // BT_ACTION_H

View File

@ -13,6 +13,11 @@
#include "bt_task.h" #include "bt_task.h"
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/engine.hpp>
using namespace godot;
#endif
Ref<BTTask> BTComment::clone() const { Ref<BTTask> BTComment::clone() const {
if (Engine::get_singleton()->is_editor_hint()) { if (Engine::get_singleton()->is_editor_hint()) {
return BTTask::clone(); return BTTask::clone();
@ -20,7 +25,7 @@ Ref<BTTask> BTComment::clone() const {
return nullptr; return nullptr;
} }
PackedStringArray BTComment::get_configuration_warnings() const { PackedStringArray BTComment::get_configuration_warnings() {
PackedStringArray warnings = BTTask::get_configuration_warnings(); PackedStringArray warnings = BTTask::get_configuration_warnings();
if (get_child_count_excluding_comments() > 0) { if (get_child_count_excluding_comments() > 0) {
warnings.append("Can only have other comment tasks as children."); warnings.append("Can only have other comment tasks as children.");

View File

@ -20,7 +20,7 @@ class BTComment : public BTTask {
public: public:
virtual Ref<BTTask> clone() const override; virtual Ref<BTTask> clone() const override;
virtual PackedStringArray get_configuration_warnings() const override; virtual PackedStringArray get_configuration_warnings() override;
}; };
#endif // BT_COMMENT #endif // BT_COMMENT

View File

@ -11,7 +11,7 @@
#include "bt_composite.h" #include "bt_composite.h"
PackedStringArray BTComposite::get_configuration_warnings() const { PackedStringArray BTComposite::get_configuration_warnings() {
PackedStringArray warnings = BTTask::get_configuration_warnings(); PackedStringArray warnings = BTTask::get_configuration_warnings();
if (get_child_count_excluding_comments() < 1) { if (get_child_count_excluding_comments() < 1) {
warnings.append("Composite should have at least one child task."); warnings.append("Composite should have at least one child task.");

View File

@ -18,7 +18,7 @@ class BTComposite : public BTTask {
GDCLASS(BTComposite, BTTask); GDCLASS(BTComposite, BTTask);
public: public:
virtual PackedStringArray get_configuration_warnings() const override; virtual PackedStringArray get_configuration_warnings() override;
}; };
#endif // BT_COMPOSITE_H #endif // BT_COMPOSITE_H

View File

@ -11,7 +11,7 @@
#include "bt_condition.h" #include "bt_condition.h"
PackedStringArray BTCondition::get_configuration_warnings() const { PackedStringArray BTCondition::get_configuration_warnings() {
PackedStringArray warnings = BTTask::get_configuration_warnings(); PackedStringArray warnings = BTTask::get_configuration_warnings();
if (get_child_count_excluding_comments() != 0) { if (get_child_count_excluding_comments() != 0) {
warnings.append("Condition task can't have child tasks."); warnings.append("Condition task can't have child tasks.");

View File

@ -18,7 +18,7 @@ class BTCondition : public BTTask {
GDCLASS(BTCondition, BTTask); GDCLASS(BTCondition, BTTask);
public: public:
virtual PackedStringArray get_configuration_warnings() const override; virtual PackedStringArray get_configuration_warnings() override;
}; };
#endif // BT_CONDITION_H #endif // BT_CONDITION_H

View File

@ -11,7 +11,7 @@
#include "bt_decorator.h" #include "bt_decorator.h"
PackedStringArray BTDecorator::get_configuration_warnings() const { PackedStringArray BTDecorator::get_configuration_warnings() {
PackedStringArray warnings = BTTask::get_configuration_warnings(); PackedStringArray warnings = BTTask::get_configuration_warnings();
if (get_child_count_excluding_comments() != 1) { if (get_child_count_excluding_comments() != 1) {
warnings.append("Decorator should have a single child task."); warnings.append("Decorator should have a single child task.");

View File

@ -18,7 +18,7 @@ class BTDecorator : public BTTask {
GDCLASS(BTDecorator, BTTask) GDCLASS(BTDecorator, BTTask)
public: public:
virtual PackedStringArray get_configuration_warnings() const override; virtual PackedStringArray get_configuration_warnings() override;
}; };
#endif // BT_DECORATOR_H #endif // BT_DECORATOR_H

View File

@ -10,7 +10,14 @@
*/ */
#include "bt_task.h" #include "bt_task.h"
#include "godot_cpp/classes/global_constants.hpp"
#include "godot_cpp/variant/dictionary.hpp"
#include "godot_cpp/variant/string_name.hpp"
#include "godot_cpp/variant/typed_array.hpp"
#include "godot_cpp/variant/utility_functions.hpp"
#include "godot_cpp/variant/variant.hpp"
#ifdef LIMBOAI_MODULE
#include "bt_comment.h" #include "bt_comment.h"
#include "modules/limboai/blackboard/blackboard.h" #include "modules/limboai/blackboard/blackboard.h"
#include "modules/limboai/util/limbo_string_names.h" #include "modules/limboai/util/limbo_string_names.h"
@ -25,6 +32,15 @@
#include "core/string/ustring.h" #include "core/string/ustring.h"
#include "core/templates/hash_map.h" #include "core/templates/hash_map.h"
#include "core/variant/variant.h" #include "core/variant/variant.h"
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include "blackboard/blackboard.h"
#include "bt/tasks/bt_comment.h"
#include "util/limbo_string_names.h"
#include <godot_cpp/classes/ref.hpp>
#endif // LIMBOAI_GDEXTENSION
void BT::_bind_methods() { void BT::_bind_methods() {
BIND_ENUM_CONSTANT(FRESH); BIND_ENUM_CONSTANT(FRESH);
@ -33,7 +49,8 @@ void BT::_bind_methods() {
BIND_ENUM_CONSTANT(SUCCESS); BIND_ENUM_CONSTANT(SUCCESS);
} }
String BTTask::_generate_name() const { String BTTask::_generate_name() {
#ifdef LIMBOAI_MODULE
if (get_script_instance()) { if (get_script_instance()) {
if (get_script_instance()->has_method(LimboStringNames::get_singleton()->_generate_name)) { if (get_script_instance()->has_method(LimboStringNames::get_singleton()->_generate_name)) {
ERR_FAIL_COND_V_MSG(!get_script_instance()->get_script()->is_tool(), "ERROR: not a tool script", "Task script should be a \"tool\" script!"); ERR_FAIL_COND_V_MSG(!get_script_instance()->get_script()->is_tool(), "ERROR: not a tool script", "Task script should be a \"tool\" script!");
@ -46,6 +63,14 @@ String BTTask::_generate_name() const {
} }
} }
return get_class().trim_prefix("BT"); return get_class().trim_prefix("BT");
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
if (!get_path().is_empty()) {
return get_path().get_basename().get_file().trim_prefix("BT").to_pascal_case();
}
return get_class().trim_prefix("BT");
#endif // LIMBOAI_GDEXTENSION
} }
Array BTTask::_get_children() const { Array BTTask::_get_children() const {
@ -72,9 +97,9 @@ void BTTask::_set_children(Array p_children) {
} }
} }
String BTTask::get_task_name() const { String BTTask::get_task_name() {
if (data.custom_name.is_empty()) { if (data.custom_name.is_empty()) {
return _generate_name(); return call(LimboStringNames::get_singleton()->_generate_name);
} }
return data.custom_name; return data.custom_name;
} }
@ -103,9 +128,15 @@ void BTTask::initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard) {
get_child(i)->initialize(p_agent, p_blackboard); get_child(i)->initialize(p_agent, p_blackboard);
} }
#ifdef LIMBOAI_MODULE
if (!GDVIRTUAL_CALL(_setup)) { if (!GDVIRTUAL_CALL(_setup)) {
_setup(); _setup();
} }
#endif
#ifdef LIMBOAI_GDEXTENSION
call(LimboStringNames::get_singleton()->_setup);
#endif
} }
Ref<BTTask> BTTask::clone() const { Ref<BTTask> BTTask::clone() const {
@ -129,6 +160,7 @@ Ref<BTTask> BTTask::clone() const {
inst->data.children.resize(data.children.size() - num_null); inst->data.children.resize(data.children.size() - num_null);
} }
#ifdef LIMBOAI_MODULE
// Make BBParam properties unique. // Make BBParam properties unique.
List<PropertyInfo> props; List<PropertyInfo> props;
inst->get_property_list(&props); inst->get_property_list(&props);
@ -154,6 +186,37 @@ Ref<BTTask> BTTask::clone() const {
} }
} }
} }
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
// Make BBParam properties unique.
TypedArray<Dictionary> props = inst->get_property_list();
HashMap<Ref<Resource>, Ref<Resource>> duplicates;
for (int i = 0; i < props.size(); i++) {
Dictionary prop = props[i];
if (!(int(prop["usage"]) & PROPERTY_USAGE_STORAGE)) {
continue;
}
StringName prop_name = prop["name"];
Variant v = inst->get(prop_name);
if (v.get_type() == Variant::OBJECT && int(prop["hint"]) == PROPERTY_HINT_RESOURCE_TYPE) {
Ref<RefCounted> ref = v;
if (ref.is_valid()) {
Ref<Resource> res = ref;
if (res.is_valid() && res->is_class("BBParam")) {
if (!duplicates.has(res)) {
duplicates[res] = res->duplicate();
}
res = duplicates[res];
inst->set(prop_name, res);
}
}
}
}
#endif // LIMBOAI_GDEXTENSION
return inst; return inst;
} }
@ -166,21 +229,38 @@ BT::Status BTTask::execute(double p_delta) {
data.children.get(i)->abort(); data.children.get(i)->abort();
} }
} }
#ifdef LIMBOAI_MODULE
if (!GDVIRTUAL_CALL(_enter)) { if (!GDVIRTUAL_CALL(_enter)) {
_enter(); _enter();
} }
#endif
#ifdef LIMBOAI_GDEXTENSION
call(LimboStringNames::get_singleton()->_enter);
#endif
} else { } else {
data.elapsed += p_delta; data.elapsed += p_delta;
} }
#ifdef LIMBOAI_MODULE
if (!GDVIRTUAL_CALL(_tick, p_delta, data.status)) { if (!GDVIRTUAL_CALL(_tick, p_delta, data.status)) {
data.status = _tick(p_delta); data.status = _tick(p_delta);
} }
#endif
#ifdef LIMBOAI_GDEXTENSION
data.status = (Status)(int)call(LimboStringNames::get_singleton()->_tick, p_delta);
#endif
if (data.status != RUNNING) { if (data.status != RUNNING) {
#ifdef LIMBOAI_MODULE
if (!GDVIRTUAL_CALL(_exit)) { if (!GDVIRTUAL_CALL(_exit)) {
_exit(); _exit();
} }
#endif
#ifdef LIMBOAI_GDEXTENSION
call(LimboStringNames::get_singleton()->_exit);
#endif
data.elapsed = 0.0; data.elapsed = 0.0;
} }
return data.status; return data.status;
@ -191,9 +271,14 @@ void BTTask::abort() {
get_child(i)->abort(); get_child(i)->abort();
} }
if (data.status == RUNNING) { if (data.status == RUNNING) {
#ifdef LIMBOAI_MODULE
if (!GDVIRTUAL_CALL(_exit)) { if (!GDVIRTUAL_CALL(_exit)) {
_exit(); _exit();
} }
#endif
#ifdef LIMBOAI_GDEXTENSION
call(LimboStringNames::get_singleton()->_exit);
#endif
} }
data.status = FRESH; data.status = FRESH;
data.elapsed = 0.0; data.elapsed = 0.0;
@ -202,9 +287,16 @@ void BTTask::abort() {
int BTTask::get_child_count_excluding_comments() const { int BTTask::get_child_count_excluding_comments() const {
int count = 0; int count = 0;
for (int i = 0; i < data.children.size(); i++) { for (int i = 0; i < data.children.size(); i++) {
#ifdef LIMBOAI_MODULE
if (!data.children[i]->is_class_ptr(BTComment::get_class_ptr_static())) { if (!data.children[i]->is_class_ptr(BTComment::get_class_ptr_static())) {
count += 1; count += 1;
} }
#endif
#ifdef LIMBOAI_GDEXTENSION
if (data.children[i]->get_class_static() != BTComment::get_class_static()) {
count += 1;
}
#endif
} }
return count; return count;
} }
@ -274,23 +366,36 @@ Ref<BTTask> BTTask::next_sibling() const {
return Ref<BTTask>(); return Ref<BTTask>();
} }
PackedStringArray BTTask::get_configuration_warnings() const { PackedStringArray BTTask::get_configuration_warnings() {
PackedStringArray ret; PackedStringArray ret;
PackedStringArray warnings; PackedStringArray warnings;
#ifdef LIMBOAI_MODULE
if (GDVIRTUAL_CALL(_get_configuration_warning, warnings)) { if (GDVIRTUAL_CALL(_get_configuration_warning, warnings)) {
ret.append_array(warnings); ret.append_array(warnings);
} }
#endif
#ifdef LIMBOAI_GDEXTENSION
warnings = call(LimboStringNames::get_singleton()->_get_configuration_warning);
ret.append_array(warnings);
#endif
return ret; return ret;
} }
void BTTask::print_tree(int p_initial_tabs) const { void BTTask::print_tree(int p_initial_tabs) {
String tabs = "--"; String tabs = "--";
for (int i = 0; i < p_initial_tabs; i++) { for (int i = 0; i < p_initial_tabs; i++) {
tabs += "--"; tabs += "--";
} }
#ifdef LIMBOAI_MODULE
print_line(vformat("%s Name: %s Instance: %s", tabs, get_task_name(), Ref<BTTask>(this))); print_line(vformat("%s Name: %s Instance: %s", tabs, get_task_name(), Ref<BTTask>(this)));
#endif
#ifdef LIMBOAI_GDEXTENSION
UtilityFunctions::print(vformat("%s Name: %s Instance: %s", tabs, get_task_name(), Ref<BTTask>(this)));
#endif
for (int i = 0; i < get_child_count(); i++) { for (int i = 0; i < get_child_count(); i++) {
get_child(i)->print_tree(p_initial_tabs + 1); get_child(i)->print_tree(p_initial_tabs + 1);
} }
@ -338,12 +443,22 @@ void BTTask::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "status", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_status"); ADD_PROPERTY(PropertyInfo(Variant::INT, "status", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_status");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "elapsed_time", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_elapsed_time"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "elapsed_time", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_elapsed_time");
#ifdef LIMBOAI_MODULE
GDVIRTUAL_BIND(_setup); GDVIRTUAL_BIND(_setup);
GDVIRTUAL_BIND(_enter); GDVIRTUAL_BIND(_enter);
GDVIRTUAL_BIND(_exit); GDVIRTUAL_BIND(_exit);
GDVIRTUAL_BIND(_tick, "p_delta"); GDVIRTUAL_BIND(_tick, "p_delta");
GDVIRTUAL_BIND(_generate_name); GDVIRTUAL_BIND(_generate_name);
GDVIRTUAL_BIND(_get_configuration_warning); GDVIRTUAL_BIND(_get_configuration_warning);
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
ClassDB::bind_method(D_METHOD("_setup"), &BTTask::_setup);
ClassDB::bind_method(D_METHOD("_enter"), &BTTask::_enter);
ClassDB::bind_method(D_METHOD("_exit"), &BTTask::_exit);
ClassDB::bind_method(D_METHOD("_tick", "p_delta"), &BTTask::_tick);
ClassDB::bind_method(D_METHOD("_generate_name"), &BTTask::_generate_name);
ClassDB::bind_method(D_METHOD("_get_configuration_warnings"), &BTTask::get_configuration_warnings);
#endif
} }
BTTask::BTTask() { BTTask::BTTask() {

View File

@ -12,6 +12,7 @@
#ifndef BTTASK_H #ifndef BTTASK_H
#define BTTASK_H #define BTTASK_H
#ifdef LIMBOAI_MODULE
#include "modules/limboai/blackboard/blackboard.h" #include "modules/limboai/blackboard/blackboard.h"
#include "modules/limboai/util/limbo_task_db.h" #include "modules/limboai/util/limbo_task_db.h"
@ -25,6 +26,18 @@
#include "core/variant/binder_common.h" #include "core/variant/binder_common.h"
#include "core/variant/dictionary.h" #include "core/variant/dictionary.h"
#include "scene/resources/texture.h" #include "scene/resources/texture.h"
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include "blackboard/blackboard.h"
#include "util/limbo_task_db.h"
#include <godot_cpp/classes/resource.hpp>
#include <godot_cpp/core/object.hpp>
#include <godot_cpp/templates/vector.hpp>
using namespace godot;
#endif // LIMBOAI_GDEXTENSION
/** /**
* Base class for BTTask. * Base class for BTTask.
@ -72,34 +85,40 @@ private:
protected: protected:
static void _bind_methods(); static void _bind_methods();
virtual String _generate_name() const; virtual String _generate_name();
virtual void _setup() {} virtual void _setup() {}
virtual void _enter() {} virtual void _enter() {}
virtual void _exit() {} virtual void _exit() {}
virtual Status _tick(double p_delta) { return FAILURE; } virtual Status _tick(double p_delta) { return FAILURE; }
#ifdef LIMBOAI_MODULE
GDVIRTUAL0RC(String, _generate_name); GDVIRTUAL0RC(String, _generate_name);
GDVIRTUAL0(_setup); GDVIRTUAL0(_setup);
GDVIRTUAL0(_enter); GDVIRTUAL0(_enter);
GDVIRTUAL0(_exit); GDVIRTUAL0(_exit);
GDVIRTUAL1R(Status, _tick, double); GDVIRTUAL1R(Status, _tick, double);
GDVIRTUAL0RC(PackedStringArray, _get_configuration_warning); GDVIRTUAL0RC(PackedStringArray, _get_configuration_warning);
#endif // LIMBOAI_MODULE
public: public:
// TODO: GDExtension doesn't have this method hmm...
#ifdef LIMBOAI_MODULE
virtual bool editor_can_reload_from_file() override { return false; } virtual bool editor_can_reload_from_file() override { return false; }
#endif // LIMBOAI_MODULE
_FORCE_INLINE_ Node *get_agent() const { return data.agent; } _FORCE_INLINE_ Node *get_agent() const { return data.agent; }
void set_agent(Node *p_agent) { data.agent = p_agent; } void set_agent(Node *p_agent) { data.agent = p_agent; }
String get_custom_name() const { return data.custom_name; } String get_custom_name() const { return data.custom_name; }
void set_custom_name(const String &p_name); void set_custom_name(const String &p_name);
String get_task_name() const; String get_task_name();
Ref<BTTask> get_root() const; Ref<BTTask> get_root() const;
virtual Ref<BTTask> clone() const; virtual Ref<BTTask> clone() const;
virtual void initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard); virtual void initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard);
virtual PackedStringArray get_configuration_warnings() const; virtual PackedStringArray get_configuration_warnings();
Status execute(double p_delta); Status execute(double p_delta);
void abort(); void abort();
@ -129,7 +148,7 @@ public:
bool is_descendant_of(const Ref<BTTask> &p_task) const; bool is_descendant_of(const Ref<BTTask> &p_task) const;
Ref<BTTask> next_sibling() const; Ref<BTTask> next_sibling() const;
void print_tree(int p_initial_tabs = 0) const; void print_tree(int p_initial_tabs = 0);
BTTask(); BTTask();
~BTTask(); ~BTTask();

View File

@ -10,23 +10,22 @@
*/ */
#include "limbo_string_names.h" #include "limbo_string_names.h"
#include "godot_cpp/variant/string_name.hpp"
#include "core/string/string_name.h"
LimboStringNames *LimboStringNames::singleton = nullptr; LimboStringNames *LimboStringNames::singleton = nullptr;
LimboStringNames::LimboStringNames() { LimboStringNames::LimboStringNames() {
_generate_name = StaticCString::create("_generate_name"); _generate_name = StringName("_generate_name");
_setup = StaticCString::create("_setup"); _setup = StringName("_setup");
_enter = StaticCString::create("_enter"); _enter = StringName("_enter");
_exit = StaticCString::create("_exit"); _exit = StringName("_exit");
_tick = StaticCString::create("_tick"); _tick = StringName("_tick");
behavior_tree_finished = StaticCString::create("behavior_tree_finished"); behavior_tree_finished = StringName("behavior_tree_finished");
setup = StaticCString::create("setup"); setup = StringName("setup");
entered = StaticCString::create("entered"); entered = StringName("entered");
exited = StaticCString::create("exited"); exited = StringName("exited");
updated = StaticCString::create("updated"); updated = StringName("updated");
_update = StaticCString::create("_update"); _update = StringName("_update");
state_changed = StaticCString::create("state_changed"); state_changed = StringName("state_changed");
_get_configuration_warning = StaticCString::create("_get_configuration_warning"); _get_configuration_warning = StringName("_get_configuration_warning");
} }

View File

@ -12,10 +12,16 @@
#ifndef LIMBO_STRING_NAMES_H #ifndef LIMBO_STRING_NAMES_H
#define LIMBO_STRING_NAMES_H #define LIMBO_STRING_NAMES_H
#include "modules/register_module_types.h" #ifdef LIMBOAI_MODULE
#include "core/string/string_name.h" #include "core/string/string_name.h"
#include "core/typedefs.h" #include "core/typedefs.h"
#include "modules/register_module_types.h"
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/variant/string_name.hpp>
using namespace godot;
#endif // LIMBOAI_GDEXTENSION
class LimboStringNames { class LimboStringNames {
friend void initialize_limboai_module(ModuleInitializationLevel p_level); friend void initialize_limboai_module(ModuleInitializationLevel p_level);

View File

@ -11,8 +11,16 @@
#include "limbo_task_db.h" #include "limbo_task_db.h"
#ifdef LIMBOAI_MODULE
#include "core/config/project_settings.h" #include "core/config/project_settings.h"
#include "core/io/dir_access.h" #include "core/io/dir_access.h"
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/dir_access.hpp>
#include <godot_cpp/classes/project_settings.hpp>
using namespace godot;
#endif // LIMBOAI_GDEXTENSION
HashMap<String, List<String>> LimboTaskDB::core_tasks; HashMap<String, List<String>> LimboTaskDB::core_tasks;
HashMap<String, List<String>> LimboTaskDB::tasks_cache; HashMap<String, List<String>> LimboTaskDB::tasks_cache;
@ -21,7 +29,14 @@ _FORCE_INLINE_ void _populate_scripted_tasks_from_dir(String p_path, List<String
if (p_path.is_empty()) { if (p_path.is_empty()) {
return; return;
} }
#ifdef LIMBOAI_MODULE
Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_RESOURCES); Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_RESOURCES);
#endif
#ifdef LIMBOAI_GDEXTENSION
Ref<DirAccess> dir = memnew(DirAccess);
#endif
if (dir->change_dir(p_path) == OK) { if (dir->change_dir(p_path) == OK) {
dir->list_dir_begin(); dir->list_dir_begin();
String fn = dir->get_next(); String fn = dir->get_next();
@ -42,7 +57,14 @@ _FORCE_INLINE_ void _populate_from_user_dir(String p_path, HashMap<String, List<
if (p_path.is_empty()) { if (p_path.is_empty()) {
return; return;
} }
#ifdef LIMBOAI_MODULE
Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_RESOURCES); Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_RESOURCES);
#endif
#ifdef LIMBOAI_GDEXTENSION
Ref<DirAccess> dir = memnew(DirAccess);
#endif
if (dir->change_dir(p_path) == OK) { if (dir->change_dir(p_path) == OK) {
dir->list_dir_begin(); dir->list_dir_begin();
String fn = dir->get_next(); String fn = dir->get_next();
@ -80,7 +102,7 @@ void LimboTaskDB::scan_user_tasks() {
} }
for (int i = 1; i < 4; i++) { for (int i = 1; i < 4; i++) {
String dir1 = GLOBAL_GET("limbo_ai/behavior_tree/user_task_dir_" + itos(i)); String dir1 = ProjectSettings::get_singleton()->get_setting_with_override("limbo_ai/behavior_tree/user_task_dir_" + itos(i));
_populate_from_user_dir(dir1, &tasks_cache); _populate_from_user_dir(dir1, &tasks_cache);
} }

View File

@ -12,9 +12,19 @@
#ifndef LIMBO_TASK_DB_H #ifndef LIMBO_TASK_DB_H
#define LIMBO_TASK_DB_H #define LIMBO_TASK_DB_H
#ifdef LIMBOAI_MODULE
#include "core/object/class_db.h" #include "core/object/class_db.h"
#include "core/templates/hash_map.h" #include "core/templates/hash_map.h"
#include "core/templates/list.h" #include "core/templates/list.h"
#endif
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/templates/hash_map.hpp>
#include <godot_cpp/templates/list.hpp>
#include <godot_cpp/variant/string.hpp>
using namespace godot;
#endif
class LimboTaskDB { class LimboTaskDB {
private: private:
@ -54,10 +64,16 @@ public:
} }
}; };
#ifdef LIMBOAI_MODULE
#define LIMBO_REGISTER_TASK(m_class) \ #define LIMBO_REGISTER_TASK(m_class) \
if (m_class::_class_is_enabled) { \ if (m_class::_class_is_enabled) { \
::LimboTaskDB::register_task<m_class>(); \ ::LimboTaskDB::register_task<m_class>(); \
} }
#endif
#ifdef LIMBOAI_GDEXTENSION
#define LIMBO_REGISTER_TASK(m_class) LimboTaskDB::register_task<m_class>();
#endif
#define TASK_CATEGORY(m_cat) \ #define TASK_CATEGORY(m_cat) \
public: \ public: \

View File

@ -11,6 +11,8 @@
#include "limbo_utility.h" #include "limbo_utility.h"
#ifdef LIMBOAI_MODULE
#include "modules/limboai/bt/tasks/bt_task.h" #include "modules/limboai/bt/tasks/bt_task.h"
#include "core/error/error_macros.h" #include "core/error/error_macros.h"
@ -22,6 +24,14 @@
#include "editor/editor_node.h" #include "editor/editor_node.h"
#endif // TOOLS_ENABLED #endif // TOOLS_ENABLED
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include "bt/tasks/bt_task.h"
#include <godot_cpp/core/error_macros.hpp>
#endif
LimboUtility *LimboUtility::singleton = nullptr; LimboUtility *LimboUtility::singleton = nullptr;
LimboUtility *LimboUtility::get_singleton() { LimboUtility *LimboUtility::get_singleton() {
@ -124,29 +134,60 @@ String LimboUtility::get_check_operator_string(CheckType p_check_type) const {
} }
bool LimboUtility::perform_check(CheckType p_check_type, const Variant &left_value, const Variant &right_value) { bool LimboUtility::perform_check(CheckType p_check_type, const Variant &left_value, const Variant &right_value) {
Variant ret;
#ifdef LIMBOAI_MODULE
switch (p_check_type) { switch (p_check_type) {
case LimboUtility::CheckType::CHECK_EQUAL: { case LimboUtility::CheckType::CHECK_EQUAL: {
return Variant::evaluate(Variant::OP_EQUAL, left_value, right_value); ret = Variant::evaluate(Variant::OP_EQUAL, left_value, right_value);
} break; } break;
case LimboUtility::CheckType::CHECK_LESS_THAN: { case LimboUtility::CheckType::CHECK_LESS_THAN: {
return Variant::evaluate(Variant::OP_LESS, left_value, right_value); ret = Variant::evaluate(Variant::OP_LESS, left_value, right_value);
} break; } break;
case LimboUtility::CheckType::CHECK_LESS_THAN_OR_EQUAL: { case LimboUtility::CheckType::CHECK_LESS_THAN_OR_EQUAL: {
return Variant::evaluate(Variant::OP_LESS_EQUAL, left_value, right_value); ret = Variant::evaluate(Variant::OP_LESS_EQUAL, left_value, right_value);
} break; } break;
case LimboUtility::CheckType::CHECK_GREATER_THAN: { case LimboUtility::CheckType::CHECK_GREATER_THAN: {
return Variant::evaluate(Variant::OP_GREATER, left_value, right_value); ret = Variant::evaluate(Variant::OP_GREATER, left_value, right_value);
} break; } break;
case LimboUtility::CheckType::CHECK_GREATER_THAN_OR_EQUAL: { case LimboUtility::CheckType::CHECK_GREATER_THAN_OR_EQUAL: {
return Variant::evaluate(Variant::OP_GREATER_EQUAL, left_value, right_value); ret = Variant::evaluate(Variant::OP_GREATER_EQUAL, left_value, right_value);
} break; } break;
case LimboUtility::CheckType::CHECK_NOT_EQUAL: { case LimboUtility::CheckType::CHECK_NOT_EQUAL: {
return Variant::evaluate(Variant::OP_NOT_EQUAL, left_value, right_value); ret = Variant::evaluate(Variant::OP_NOT_EQUAL, left_value, right_value);
} break;
default: {
ret = false;
} break;
}
#endif
#ifdef LIMBOAI_GDEXTENSION
bool valid;
switch (p_check_type) {
case LimboUtility::CheckType::CHECK_EQUAL: {
Variant::evaluate(Variant::OP_LESS, left_value, right_value, ret, valid);
} break;
case LimboUtility::CheckType::CHECK_LESS_THAN: {
Variant::evaluate(Variant::OP_LESS, left_value, right_value, ret, valid);
} break;
case LimboUtility::CheckType::CHECK_LESS_THAN_OR_EQUAL: {
Variant::evaluate(Variant::OP_LESS_EQUAL, left_value, right_value, ret, valid);
} break;
case LimboUtility::CheckType::CHECK_GREATER_THAN: {
Variant::evaluate(Variant::OP_GREATER, left_value, right_value, ret, valid);
} break;
case LimboUtility::CheckType::CHECK_GREATER_THAN_OR_EQUAL: {
Variant::evaluate(Variant::OP_GREATER_EQUAL, left_value, right_value, ret, valid);
} break;
case LimboUtility::CheckType::CHECK_NOT_EQUAL: {
Variant::evaluate(Variant::OP_NOT_EQUAL, left_value, right_value, ret, valid);
} break; } break;
default: { default: {
return false; return false;
} break; } break;
} }
#endif
return ret;
} }
String LimboUtility::get_operation_string(Operation p_operation) const { String LimboUtility::get_operation_string(Operation p_operation) const {
@ -192,44 +233,91 @@ String LimboUtility::get_operation_string(Operation p_operation) const {
} }
Variant LimboUtility::perform_operation(Operation p_operation, const Variant &left_value, const Variant &right_value) { Variant LimboUtility::perform_operation(Operation p_operation, const Variant &left_value, const Variant &right_value) {
Variant ret;
#ifdef LIMBOAI_MODULE
switch (p_operation) { switch (p_operation) {
case OPERATION_NONE: { case OPERATION_NONE: {
return right_value; ret = right_value;
} break; } break;
case OPERATION_ADDITION: { case OPERATION_ADDITION: {
return Variant::evaluate(Variant::OP_ADD, left_value, right_value); ret = Variant::evaluate(Variant::OP_ADD, left_value, right_value);
} break; } break;
case OPERATION_SUBTRACTION: { case OPERATION_SUBTRACTION: {
return Variant::evaluate(Variant::OP_SUBTRACT, left_value, right_value); ret = Variant::evaluate(Variant::OP_SUBTRACT, left_value, right_value);
} break; } break;
case OPERATION_MULTIPLICATION: { case OPERATION_MULTIPLICATION: {
return Variant::evaluate(Variant::OP_MULTIPLY, left_value, right_value); ret = Variant::evaluate(Variant::OP_MULTIPLY, left_value, right_value);
} break; } break;
case OPERATION_DIVISION: { case OPERATION_DIVISION: {
return Variant::evaluate(Variant::OP_DIVIDE, left_value, right_value); ret = Variant::evaluate(Variant::OP_DIVIDE, left_value, right_value);
} break; } break;
case OPERATION_MODULO: { case OPERATION_MODULO: {
return Variant::evaluate(Variant::OP_MODULE, left_value, right_value); ret = Variant::evaluate(Variant::OP_MODULE, left_value, right_value);
} break; } break;
case OPERATION_POWER: { case OPERATION_POWER: {
return Variant::evaluate(Variant::OP_POWER, left_value, right_value); ret = Variant::evaluate(Variant::OP_POWER, left_value, right_value);
} break; } break;
case OPERATION_BIT_SHIFT_LEFT: { case OPERATION_BIT_SHIFT_LEFT: {
return Variant::evaluate(Variant::OP_SHIFT_LEFT, left_value, right_value); ret = Variant::evaluate(Variant::OP_SHIFT_LEFT, left_value, right_value);
} break; } break;
case OPERATION_BIT_SHIFT_RIGHT: { case OPERATION_BIT_SHIFT_RIGHT: {
return Variant::evaluate(Variant::OP_SHIFT_RIGHT, left_value, right_value); ret = Variant::evaluate(Variant::OP_SHIFT_RIGHT, left_value, right_value);
} break; } break;
case OPERATION_BIT_AND: { case OPERATION_BIT_AND: {
return Variant::evaluate(Variant::OP_BIT_AND, left_value, right_value); ret = Variant::evaluate(Variant::OP_BIT_AND, left_value, right_value);
} break; } break;
case OPERATION_BIT_OR: { case OPERATION_BIT_OR: {
return Variant::evaluate(Variant::OP_BIT_OR, left_value, right_value); ret = Variant::evaluate(Variant::OP_BIT_OR, left_value, right_value);
} break; } break;
case OPERATION_BIT_XOR: { case OPERATION_BIT_XOR: {
return Variant::evaluate(Variant::OP_BIT_XOR, left_value, right_value); ret = Variant::evaluate(Variant::OP_BIT_XOR, left_value, right_value);
} break; } break;
} }
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
bool valid;
switch (p_operation) {
case OPERATION_NONE: {
ret = right_value;
} break;
case OPERATION_ADDITION: {
Variant::evaluate(Variant::OP_ADD, left_value, right_value, ret, valid);
} break;
case OPERATION_SUBTRACTION: {
Variant::evaluate(Variant::OP_SUBTRACT, left_value, right_value, ret, valid);
} break;
case OPERATION_MULTIPLICATION: {
Variant::evaluate(Variant::OP_MULTIPLY, left_value, right_value, ret, valid);
} break;
case OPERATION_DIVISION: {
Variant::evaluate(Variant::OP_DIVIDE, left_value, right_value, ret, valid);
} break;
case OPERATION_MODULO: {
Variant::evaluate(Variant::OP_MODULE, left_value, right_value, ret, valid);
} break;
// TODO: Uncomment when https://github.com/godotengine/godot-cpp/issues/1348 is fixed.
// case OPERATION_POWER: {
// Variant::evaluate(Variant::OP_POWER, left_value, right_value, ret, valid);
// } break;
case OPERATION_BIT_SHIFT_LEFT: {
Variant::evaluate(Variant::OP_SHIFT_LEFT, left_value, right_value, ret, valid);
} break;
case OPERATION_BIT_SHIFT_RIGHT: {
Variant::evaluate(Variant::OP_SHIFT_RIGHT, left_value, right_value, ret, valid);
} break;
case OPERATION_BIT_AND: {
Variant::evaluate(Variant::OP_BIT_AND, left_value, right_value, ret, valid);
} break;
case OPERATION_BIT_OR: {
Variant::evaluate(Variant::OP_BIT_OR, left_value, right_value, ret, valid);
} break;
case OPERATION_BIT_XOR: {
Variant::evaluate(Variant::OP_BIT_XOR, left_value, right_value, ret, valid);
} break;
}
#endif // LIMBOAI_GDEXTENSION
return Variant(); return Variant();
} }

View File

@ -12,12 +12,23 @@
#ifndef LIMBO_UTILITY_H #ifndef LIMBO_UTILITY_H
#define LIMBO_UTILITY_H #define LIMBO_UTILITY_H
#ifdef LIMBOAI_MODULE
#include "core/object/object.h" #include "core/object/object.h"
#include "core/object/class_db.h" #include "core/object/class_db.h"
#include "core/variant/binder_common.h" #include "core/variant/binder_common.h"
#include "core/variant/variant.h" #include "core/variant/variant.h"
#include "scene/resources/texture.h" #include "scene/resources/texture.h"
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/object.hpp>
#include <godot_cpp/classes/texture2d.hpp>
#include <godot_cpp/core/binder_common.hpp>
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
#endif // LIMBOAI_GDEXTENSION
#define LOGICAL_XOR(a, b) (a) ? !(b) : (b) #define LOGICAL_XOR(a, b) (a) ? !(b) : (b)