Port LimboHSM, LimboState and BTState

This commit is contained in:
Serhii Snitsaruk 2024-01-07 05:54:17 +01:00
parent 0767c0eee1
commit f5b1b52f67
9 changed files with 102 additions and 49 deletions

View File

@ -11,21 +11,27 @@
#include "bt_state.h" #include "bt_state.h"
#include "modules/limboai/editor/debugger/limbo_debugger.h" #include "../editor/debugger/limbo_debugger.h"
#include "modules/limboai/hsm/limbo_state.h" #include "../util/limbo_def.h"
#include "modules/limboai/util/limbo_string_names.h" #include "../util/limbo_string_names.h"
#ifdef LIMBOAI_MODULE
#include "core/debugger/engine_debugger.h" #include "core/debugger/engine_debugger.h"
#include "core/error/error_macros.h" #include "core/error/error_macros.h"
#include "core/object/class_db.h" #include "core/object/class_db.h"
#include "core/variant/variant.h" #include "core/variant/variant.h"
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/engine_debugger.hpp>
#endif // LIMBOAI_GDEXTENSION
void BTState::_setup() { void BTState::_setup() {
ERR_FAIL_COND_MSG(behavior_tree.is_null(), "BTState: BehaviorTree is not assigned."); ERR_FAIL_COND_MSG(behavior_tree.is_null(), "BTState: BehaviorTree is not assigned.");
tree_instance = behavior_tree->instantiate(get_agent(), get_blackboard()); tree_instance = behavior_tree->instantiate(get_agent(), get_blackboard());
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if (tree_instance.is_valid() && EngineDebugger::is_active()) { if (tree_instance.is_valid() && IS_DEBUGGER_ACTIVE()) {
LimboDebugger::get_singleton()->register_bt_instance(tree_instance, get_path()); LimboDebugger::get_singleton()->register_bt_instance(tree_instance, get_path());
} }
#endif #endif
@ -51,12 +57,12 @@ void BTState::_update(double p_delta) {
void BTState::_notification(int p_notification) { void BTState::_notification(int p_notification) {
switch (p_notification) { switch (p_notification) {
case NOTIFICATION_ENTER_TREE: { case NOTIFICATION_ENTER_TREE: {
if (tree_instance.is_valid() && EngineDebugger::is_active()) { if (tree_instance.is_valid() && IS_DEBUGGER_ACTIVE()) {
LimboDebugger::get_singleton()->register_bt_instance(tree_instance, get_path()); LimboDebugger::get_singleton()->register_bt_instance(tree_instance, get_path());
} }
} break; } break;
case NOTIFICATION_EXIT_TREE: { case NOTIFICATION_EXIT_TREE: {
if (tree_instance.is_valid() && EngineDebugger::is_active()) { if (tree_instance.is_valid() && IS_DEBUGGER_ACTIVE()) {
LimboDebugger::get_singleton()->unregister_bt_instance(tree_instance, get_path()); LimboDebugger::get_singleton()->unregister_bt_instance(tree_instance, get_path());
} }
} break; } break;

View File

@ -12,10 +12,10 @@
#ifndef BT_STATE_H #ifndef BT_STATE_H
#define BT_STATE_H #define BT_STATE_H
#include "modules/limboai/hsm/limbo_state.h" #include "../hsm/limbo_state.h"
#include "modules/limboai/bt/behavior_tree.h" #include "../bt/behavior_tree.h"
#include "modules/limboai/bt/tasks/bt_task.h" #include "../bt/tasks/bt_task.h"
class BTState : public LimboState { class BTState : public LimboState {
GDCLASS(BTState, LimboState); GDCLASS(BTState, LimboState);

View File

@ -11,10 +11,7 @@
#include "limbo_hsm.h" #include "limbo_hsm.h"
#include "modules/limboai/blackboard/blackboard.h" #ifdef LIMBOAI_MODULE
#include "modules/limboai/hsm/limbo_state.h"
#include "modules/limboai/util/limbo_string_names.h"
#include "core/config/engine.h" #include "core/config/engine.h"
#include "core/error/error_macros.h" #include "core/error/error_macros.h"
#include "core/object/class_db.h" #include "core/object/class_db.h"
@ -22,6 +19,7 @@
#include "core/typedefs.h" #include "core/typedefs.h"
#include "core/variant/callable.h" #include "core/variant/callable.h"
#include "core/variant/variant.h" #include "core/variant/variant.h"
#endif // LIMBOAI_MODULE
VARIANT_ENUM_CAST(LimboHSM::UpdateMode); VARIANT_ENUM_CAST(LimboHSM::UpdateMode);
@ -160,12 +158,20 @@ bool LimboHSM::dispatch(const String &p_event, const Variant &p_cargo) {
if (to_state != nullptr) { if (to_state != nullptr) {
bool permitted = true; bool permitted = true;
if (to_state->guard_callable.is_valid()) { if (to_state->guard_callable.is_valid()) {
Callable::CallError ce;
Variant ret; Variant ret;
#ifdef LIMBOAI_MODULE
Callable::CallError ce;
to_state->guard_callable.callp(nullptr, 0, ret, ce); to_state->guard_callable.callp(nullptr, 0, ret, ce);
if (unlikely(ce.error != Callable::CallError::CALL_OK)) { if (unlikely(ce.error != Callable::CallError::CALL_OK)) {
ERR_PRINT_ONCE("LimboHSM: Error calling substate's guard callable: " + Variant::get_callable_error_text(to_state->guard_callable, nullptr, 0, ce)); ERR_PRINT_ONCE("LimboHSM: Error calling substate's guard callable: " + Variant::get_callable_error_text(to_state->guard_callable, nullptr, 0, ce));
} }
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
ret = to_state->guard_callable.call();
#endif // LIMBOAI_GDEXTENSION
if (unlikely(ret.get_type() != Variant::BOOL)) { if (unlikely(ret.get_type() != Variant::BOOL)) {
ERR_PRINT_ONCE(vformat("State guard callable %s returned non-boolean value (%s).", to_state->guard_callable, to_state)); ERR_PRINT_ONCE(vformat("State guard callable %s returned non-boolean value (%s).", to_state->guard_callable, to_state));
} else { } else {
@ -179,7 +185,7 @@ bool LimboHSM::dispatch(const String &p_event, const Variant &p_cargo) {
} }
} }
if (!event_consumed && p_event == EVENT_FINISHED && !(get_parent() && get_parent()->is_class("LimboState"))) { if (!event_consumed && p_event == LSNAME(EVENT_FINISHED) && !(get_parent() && get_parent()->is_class("LimboState"))) {
_exit(); _exit();
} }

View File

@ -14,10 +14,6 @@
#include "limbo_state.h" #include "limbo_state.h"
#include "core/object/object.h"
#include "core/templates/hash_map.h"
#include "core/variant/variant.h"
class LimboHSM : public LimboState { class LimboHSM : public LimboState {
GDCLASS(LimboHSM, LimboState); GDCLASS(LimboHSM, LimboState);

View File

@ -11,8 +11,9 @@
#include "limbo_state.h" #include "limbo_state.h"
#include "modules/limboai/util/limbo_string_names.h" #include "../util/limbo_def.h"
#ifdef LIMBOAI_MODULE
#include "core/error/error_macros.h" #include "core/error/error_macros.h"
#include "core/object/class_db.h" #include "core/object/class_db.h"
#include "core/object/object.h" #include "core/object/object.h"
@ -20,8 +21,10 @@
#include "core/variant/array.h" #include "core/variant/array.h"
#include "core/variant/callable.h" #include "core/variant/callable.h"
#include "core/variant/variant.h" #include "core/variant/variant.h"
#endif // LIMBOAI_MODULE
const String LimboState::EVENT_FINISHED = "finished"; #ifdef LIMBOAI_GDEXTENSION
#endif
LimboState *LimboState::get_root() const { LimboState *LimboState::get_root() const {
const LimboState *state = this; const LimboState *state = this;
@ -37,13 +40,13 @@ LimboState *LimboState::named(String p_name) {
}; };
void LimboState::_setup() { void LimboState::_setup() {
GDVIRTUAL_CALL(_setup); VCALL(_setup);
emit_signal(LimboStringNames::get_singleton()->setup); emit_signal(LimboStringNames::get_singleton()->setup);
}; };
void LimboState::_enter() { void LimboState::_enter() {
active = true; active = true;
GDVIRTUAL_CALL(_enter); VCALL(_enter);
emit_signal(LimboStringNames::get_singleton()->entered); emit_signal(LimboStringNames::get_singleton()->entered);
}; };
@ -51,13 +54,13 @@ void LimboState::_exit() {
if (!active) { if (!active) {
return; return;
} }
GDVIRTUAL_CALL(_exit); VCALL(_exit);
emit_signal(LimboStringNames::get_singleton()->exited); emit_signal(LimboStringNames::get_singleton()->exited);
active = false; active = false;
}; };
void LimboState::_update(double p_delta) { void LimboState::_update(double p_delta) {
GDVIRTUAL_CALL(_update, p_delta); VCALL_ARGS(_update, p_delta);
emit_signal(LimboStringNames::get_singleton()->updated, p_delta); emit_signal(LimboStringNames::get_singleton()->updated, p_delta);
}; };
@ -80,8 +83,10 @@ void LimboState::_initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard)
bool LimboState::dispatch(const String &p_event, const Variant &p_cargo) { bool LimboState::dispatch(const String &p_event, const Variant &p_cargo) {
ERR_FAIL_COND_V(p_event.is_empty(), false); ERR_FAIL_COND_V(p_event.is_empty(), false);
if (handlers.size() > 0 && handlers.has(p_event)) { if (handlers.size() > 0 && handlers.has(p_event)) {
Callable::CallError ce;
Variant ret; Variant ret;
#ifdef LIMBOAI_MODULE
Callable::CallError ce;
if (p_cargo.get_type() == Variant::NIL) { if (p_cargo.get_type() == Variant::NIL) {
handlers[p_event].callp(nullptr, 0, ret, ce); handlers[p_event].callp(nullptr, 0, ret, ce);
if (ce.error != Callable::CallError::CALL_OK) { if (ce.error != Callable::CallError::CALL_OK) {
@ -95,6 +100,17 @@ bool LimboState::dispatch(const String &p_event, const Variant &p_cargo) {
ERR_PRINT("Error calling event handler " + Variant::get_callable_error_text(handlers[p_event], argptrs, 1, ce)); ERR_PRINT("Error calling event handler " + Variant::get_callable_error_text(handlers[p_event], argptrs, 1, ce));
} }
} }
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
if (p_cargo.get_type() == Variant::NIL) {
ret = handlers[p_event].call();
} else {
Array args;
args.append(p_cargo);
ret = handlers[p_event].callv(args);
}
#endif // LIMBOAI_GDEXTENSION
if (unlikely(ret.get_type() != Variant::BOOL)) { if (unlikely(ret.get_type() != Variant::BOOL)) {
ERR_PRINT("Event handler returned unexpected type: " + Variant::get_type_name(ret.get_type())); ERR_PRINT("Event handler returned unexpected type: " + Variant::get_type_name(ret.get_type()));
@ -168,10 +184,18 @@ void LimboState::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_blackboard_data", "p_blackboard"), &LimboState::_set_blackboard_data); 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("_get_blackboard_data"), &LimboState::_get_blackboard_data);
#ifdef LIMBOAI_MODULE
GDVIRTUAL_BIND(_setup); GDVIRTUAL_BIND(_setup);
GDVIRTUAL_BIND(_enter); GDVIRTUAL_BIND(_enter);
GDVIRTUAL_BIND(_exit); GDVIRTUAL_BIND(_exit);
GDVIRTUAL_BIND(_update, "p_delta"); GDVIRTUAL_BIND(_update, "p_delta");
#endif
#ifdef LIMBOAI_GDEXTENSION
ClassDB::bind_method(D_METHOD("_setup"), &LimboState::_setup);
ClassDB::bind_method(D_METHOD("_enter"), &LimboState::_enter);
ClassDB::bind_method(D_METHOD("_exit"), &LimboState::_exit);
ClassDB::bind_method(D_METHOD("_update", "p_delta"), &LimboState::_update);
#endif
ADD_PROPERTY(PropertyInfo(Variant::STRING, "EVENT_FINISHED", PROPERTY_HINT_NONE, "", 0), "", "event_finished"); 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, "agent", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_agent", "get_agent");

View File

@ -12,9 +12,11 @@
#ifndef LIMBO_STATE_H #ifndef LIMBO_STATE_H
#define LIMBO_STATE_H #define LIMBO_STATE_H
#include "modules/limboai/blackboard/blackboard.h" #include "../blackboard/blackboard.h"
#include "core/object/class_db.h" #include "../util/limbo_string_names.h"
#ifdef LIMBOAI_MODULE
#include "core/object/gdvirtual.gen.inc" #include "core/object/gdvirtual.gen.inc"
#include "core/object/object.h" #include "core/object/object.h"
#include "core/string/string_name.h" #include "core/string/string_name.h"
@ -23,6 +25,11 @@
#include "core/variant/callable.h" #include "core/variant/callable.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/templates/hash_map.hpp>
#endif // LIMBOAI_GDEXTENSION
class LimboHSM; class LimboHSM;
@ -54,16 +61,16 @@ protected:
virtual void _exit(); virtual void _exit();
virtual void _update(double p_delta); virtual void _update(double p_delta);
#ifdef LIMBOAI_MODULE
GDVIRTUAL0(_setup); GDVIRTUAL0(_setup);
GDVIRTUAL0(_enter); GDVIRTUAL0(_enter);
GDVIRTUAL0(_exit); GDVIRTUAL0(_exit);
GDVIRTUAL1(_update, double); GDVIRTUAL1(_update, double);
#endif // LIMBOAI_MODULE
void add_event_handler(const String &p_event, const Callable &p_handler); void add_event_handler(const String &p_event, const Callable &p_handler);
public: public:
static const String EVENT_FINISHED;
Ref<Blackboard> get_blackboard() const { return blackboard; } Ref<Blackboard> get_blackboard() const { return blackboard; }
Node *get_agent() const { return agent; } Node *get_agent() const { return agent; }
@ -76,7 +83,7 @@ public:
LimboState *call_on_exit(const Callable &p_callable); LimboState *call_on_exit(const Callable &p_callable);
LimboState *call_on_update(const Callable &p_callable); LimboState *call_on_update(const Callable &p_callable);
_FORCE_INLINE_ String event_finished() const { return EVENT_FINISHED; } _FORCE_INLINE_ String event_finished() const { return LSNAME(EVENT_FINISHED); }
LimboState *get_root() const; LimboState *get_root() const;
bool is_active() const { return active; } bool is_active() const { return active; }

View File

@ -19,6 +19,8 @@
#define PRINT_LINE(...) (print_line(__VA_ARGS__)) #define PRINT_LINE(...) (print_line(__VA_ARGS__))
#define IS_DEBUGGER_ACTIVE() (EngineDebugger::is_active()) #define IS_DEBUGGER_ACTIVE() (EngineDebugger::is_active())
#define GET_SCENE_TREE() (SceneTree::get_singleton()) #define GET_SCENE_TREE() (SceneTree::get_singleton())
#define VCALL(m_method) (GDVIRTUAL_CALL(method))
#define VCALL_ARGS(method, ...) (call(LSNAME(method), __VA_ARGS__))
#endif // LIMBOAI_MODULE #endif // LIMBOAI_MODULE
@ -32,5 +34,7 @@
#define PRINT_LINE(...) (UtilityFunctions::print(__VA_ARGS__)) #define PRINT_LINE(...) (UtilityFunctions::print(__VA_ARGS__))
#define IS_DEBUGGER_ACTIVE() (EngineDebugger::get_singleton()->is_active()) #define IS_DEBUGGER_ACTIVE() (EngineDebugger::get_singleton()->is_active())
#define GET_SCENE_TREE() ((SceneTree *)(Engine::get_singleton()->get_main_loop())) #define GET_SCENE_TREE() ((SceneTree *)(Engine::get_singleton()->get_main_loop()))
#define VCALL(m_name) (call(LSNAME(m_name)))
#define VCALL_ARGS(m_name, ...) (call(LSNAME(m_name), __VA_ARGS__))
#endif // LIMBOAI_GDEXTENSION #endif // LIMBOAI_GDEXTENSION

View File

@ -12,27 +12,36 @@
#include "limbo_string_names.h" #include "limbo_string_names.h"
#include "godot_cpp/variant/string_name.hpp" #include "godot_cpp/variant/string_name.hpp"
#ifdef LIMBOAI_MODULE
#define SN(m_arg) (StaticCString::create(m_arg))
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
#define SN(m_arg) (StringName(m_arg))
#endif // LIMBOAI_GDEXTENSION
LimboStringNames *LimboStringNames::singleton = nullptr; LimboStringNames *LimboStringNames::singleton = nullptr;
LimboStringNames::LimboStringNames() { LimboStringNames::LimboStringNames() {
_generate_name = StringName("_generate_name"); _generate_name = SN("_generate_name");
_setup = StringName("_setup"); _setup = SN("_setup");
_enter = StringName("_enter"); _enter = SN("_enter");
_exit = StringName("_exit"); _exit = SN("_exit");
_tick = StringName("_tick"); _tick = SN("_tick");
behavior_tree_finished = StringName("behavior_tree_finished"); behavior_tree_finished = SN("behavior_tree_finished");
setup = StringName("setup"); setup = SN("setup");
entered = StringName("entered"); entered = SN("entered");
exited = StringName("exited"); exited = SN("exited");
updated = StringName("updated"); updated = SN("updated");
_update = StringName("_update"); _update = SN("_update");
state_changed = StringName("state_changed"); state_changed = SN("state_changed");
_get_configuration_warning = StringName("_get_configuration_warning"); _get_configuration_warning = SN("_get_configuration_warning");
changed = StringName("changed"); changed = SN("changed");
changed = StringName("emit_changed"); changed = SN("emit_changed");
_weight_ = StringName("_weight_"); _weight_ = SN("_weight_");
error_value = StringName("error_value"); error_value = SN("error_value");
behavior_tree = StringName("behavior_tree"); behavior_tree = SN("behavior_tree");
EVENT_FINISHED = "finished";
repeat_forever.parse_utf8("Repeat ∞"); repeat_forever.parse_utf8("Repeat ∞");
} }

View File

@ -59,6 +59,7 @@ public:
StringName error_value; StringName error_value;
StringName behavior_tree; StringName behavior_tree;
String EVENT_FINISHED;
String repeat_forever; String repeat_forever;
}; };