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 "modules/limboai/editor/debugger/limbo_debugger.h"
#include "modules/limboai/hsm/limbo_state.h"
#include "modules/limboai/util/limbo_string_names.h"
#include "../editor/debugger/limbo_debugger.h"
#include "../util/limbo_def.h"
#include "../util/limbo_string_names.h"
#ifdef LIMBOAI_MODULE
#include "core/debugger/engine_debugger.h"
#include "core/error/error_macros.h"
#include "core/object/class_db.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() {
ERR_FAIL_COND_MSG(behavior_tree.is_null(), "BTState: BehaviorTree is not assigned.");
tree_instance = behavior_tree->instantiate(get_agent(), get_blackboard());
#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());
}
#endif
@ -51,12 +57,12 @@ void BTState::_update(double p_delta) {
void BTState::_notification(int p_notification) {
switch (p_notification) {
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());
}
} break;
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());
}
} break;

View File

@ -12,10 +12,10 @@
#ifndef 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 "modules/limboai/bt/tasks/bt_task.h"
#include "../bt/behavior_tree.h"
#include "../bt/tasks/bt_task.h"
class BTState : public LimboState {
GDCLASS(BTState, LimboState);

View File

@ -11,10 +11,7 @@
#include "limbo_hsm.h"
#include "modules/limboai/blackboard/blackboard.h"
#include "modules/limboai/hsm/limbo_state.h"
#include "modules/limboai/util/limbo_string_names.h"
#ifdef LIMBOAI_MODULE
#include "core/config/engine.h"
#include "core/error/error_macros.h"
#include "core/object/class_db.h"
@ -22,6 +19,7 @@
#include "core/typedefs.h"
#include "core/variant/callable.h"
#include "core/variant/variant.h"
#endif // LIMBOAI_MODULE
VARIANT_ENUM_CAST(LimboHSM::UpdateMode);
@ -160,12 +158,20 @@ bool LimboHSM::dispatch(const String &p_event, const Variant &p_cargo) {
if (to_state != nullptr) {
bool permitted = true;
if (to_state->guard_callable.is_valid()) {
Callable::CallError ce;
Variant ret;
#ifdef LIMBOAI_MODULE
Callable::CallError ce;
to_state->guard_callable.callp(nullptr, 0, ret, ce);
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));
}
#endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION
ret = to_state->guard_callable.call();
#endif // LIMBOAI_GDEXTENSION
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));
} 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();
}

View File

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

View File

@ -11,8 +11,9 @@
#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/object/class_db.h"
#include "core/object/object.h"
@ -20,8 +21,10 @@
#include "core/variant/array.h"
#include "core/variant/callable.h"
#include "core/variant/variant.h"
#endif // LIMBOAI_MODULE
const String LimboState::EVENT_FINISHED = "finished";
#ifdef LIMBOAI_GDEXTENSION
#endif
LimboState *LimboState::get_root() const {
const LimboState *state = this;
@ -37,13 +40,13 @@ LimboState *LimboState::named(String p_name) {
};
void LimboState::_setup() {
GDVIRTUAL_CALL(_setup);
VCALL(_setup);
emit_signal(LimboStringNames::get_singleton()->setup);
};
void LimboState::_enter() {
active = true;
GDVIRTUAL_CALL(_enter);
VCALL(_enter);
emit_signal(LimboStringNames::get_singleton()->entered);
};
@ -51,13 +54,13 @@ void LimboState::_exit() {
if (!active) {
return;
}
GDVIRTUAL_CALL(_exit);
VCALL(_exit);
emit_signal(LimboStringNames::get_singleton()->exited);
active = false;
};
void LimboState::_update(double p_delta) {
GDVIRTUAL_CALL(_update, p_delta);
VCALL_ARGS(_update, 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) {
ERR_FAIL_COND_V(p_event.is_empty(), false);
if (handlers.size() > 0 && handlers.has(p_event)) {
Callable::CallError ce;
Variant ret;
#ifdef LIMBOAI_MODULE
Callable::CallError ce;
if (p_cargo.get_type() == Variant::NIL) {
handlers[p_event].callp(nullptr, 0, ret, ce);
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));
}
}
#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)) {
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("_get_blackboard_data"), &LimboState::_get_blackboard_data);
#ifdef LIMBOAI_MODULE
GDVIRTUAL_BIND(_setup);
GDVIRTUAL_BIND(_enter);
GDVIRTUAL_BIND(_exit);
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::OBJECT, "agent", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_agent", "get_agent");

View File

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

View File

@ -19,6 +19,8 @@
#define PRINT_LINE(...) (print_line(__VA_ARGS__))
#define IS_DEBUGGER_ACTIVE() (EngineDebugger::is_active())
#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
@ -32,5 +34,7 @@
#define PRINT_LINE(...) (UtilityFunctions::print(__VA_ARGS__))
#define IS_DEBUGGER_ACTIVE() (EngineDebugger::get_singleton()->is_active())
#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

View File

@ -12,27 +12,36 @@
#include "limbo_string_names.h"
#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() {
_generate_name = StringName("_generate_name");
_setup = StringName("_setup");
_enter = StringName("_enter");
_exit = StringName("_exit");
_tick = StringName("_tick");
behavior_tree_finished = StringName("behavior_tree_finished");
setup = StringName("setup");
entered = StringName("entered");
exited = StringName("exited");
updated = StringName("updated");
_update = StringName("_update");
state_changed = StringName("state_changed");
_get_configuration_warning = StringName("_get_configuration_warning");
changed = StringName("changed");
changed = StringName("emit_changed");
_weight_ = StringName("_weight_");
error_value = StringName("error_value");
behavior_tree = StringName("behavior_tree");
_generate_name = SN("_generate_name");
_setup = SN("_setup");
_enter = SN("_enter");
_exit = SN("_exit");
_tick = SN("_tick");
behavior_tree_finished = SN("behavior_tree_finished");
setup = SN("setup");
entered = SN("entered");
exited = SN("exited");
updated = SN("updated");
_update = SN("_update");
state_changed = SN("state_changed");
_get_configuration_warning = SN("_get_configuration_warning");
changed = SN("changed");
changed = SN("emit_changed");
_weight_ = SN("_weight_");
error_value = SN("error_value");
behavior_tree = SN("behavior_tree");
EVENT_FINISHED = "finished";
repeat_forever.parse_utf8("Repeat ∞");
}

View File

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