From 9645baeb30bceccec8a4a6b3721c341e8378bc72 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Tue, 9 Jan 2024 13:34:24 +0100 Subject: [PATCH] Port LimboAI plugin and editor --- bt/behavior_tree.cpp | 13 +- bt/behavior_tree.h | 1 + bt/bt_state.cpp | 2 +- bt/tasks/bt_task.cpp | 8 +- bt/tasks/bt_task.h | 2 +- bt/tasks/decorators/bt_cooldown.cpp | 2 +- editor/action_banner.cpp | 5 +- editor/action_banner.h | 6 +- editor/debugger/behavior_tree_view.cpp | 10 +- editor/debugger/limbo_debugger.cpp | 4 +- editor/limbo_ai_editor_plugin.cpp | 590 +++++++++++++---------- editor/limbo_ai_editor_plugin.h | 73 ++- editor/mode_switch_button.cpp | 9 +- editor/mode_switch_button.h | 2 + editor/task_palette.cpp | 59 ++- editor/task_palette.h | 14 +- editor/task_tree.cpp | 20 +- gdextension/SConstruct | 49 ++ gdextension/limboai.gdextension | 27 ++ hsm/limbo_state.cpp | 2 +- register_types.cpp | 114 +++-- register_types.h | 12 + util/{limbo_def.cpp => limbo_compat.cpp} | 34 +- util/limbo_compat.h | 152 ++++++ util/limbo_def.h | 85 ---- util/limbo_string_names.cpp | 140 ++++-- util/limbo_string_names.h | 136 ++++-- util/limbo_task_db.cpp | 17 +- util/limbo_utility.cpp | 144 ++---- util/limbo_utility.h | 17 + 30 files changed, 1086 insertions(+), 663 deletions(-) create mode 100644 gdextension/SConstruct create mode 100644 gdextension/limboai.gdextension rename util/{limbo_def.cpp => limbo_compat.cpp} (52%) create mode 100644 util/limbo_compat.h delete mode 100644 util/limbo_def.h diff --git a/bt/behavior_tree.cpp b/bt/behavior_tree.cpp index e3dec62..d1e4246 100644 --- a/bt/behavior_tree.cpp +++ b/bt/behavior_tree.cpp @@ -16,9 +16,11 @@ #include "core/object/class_db.h" #include "core/templates/list.h" #include "core/variant/variant.h" -#endif // LIMBOAI_MODULE +#endif // ! LIMBOAI_MODULE + #ifdef LIMBOAI_GDEXTENSION -#endif // LIMBOAI_GDEXTENSION +#include "godot_cpp/core/error_macros.hpp" +#endif // ! LIMBOAI_GDEXTENSION Ref BehaviorTree::clone() const { Ref copy = duplicate(false); @@ -29,6 +31,12 @@ Ref BehaviorTree::clone() const { return copy; } +void BehaviorTree::copy_from(const Ref &p_other) { + ERR_FAIL_COND(p_other.is_null()); + description = p_other->get_description(); + root_task = p_other->get_root_task(); +} + Ref BehaviorTree::instantiate(Node *p_agent, const Ref &p_blackboard) const { ERR_FAIL_COND_V_MSG(root_task == nullptr, memnew(BTTask), "Trying to instance a behavior tree with no valid root task."); Ref inst = root_task->clone(); @@ -42,6 +50,7 @@ void BehaviorTree::_bind_methods() { 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); + ClassDB::bind_method(D_METHOD("copy_from", "p_other"), &BehaviorTree::copy_from); 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"); diff --git a/bt/behavior_tree.h b/bt/behavior_tree.h index ca30924..5ede279 100644 --- a/bt/behavior_tree.h +++ b/bt/behavior_tree.h @@ -52,6 +52,7 @@ public: Ref get_root_task() const { return root_task; } Ref clone() const; + void copy_from(const Ref &p_other); Ref instantiate(Node *p_agent, const Ref &p_blackboard) const; }; diff --git a/bt/bt_state.cpp b/bt/bt_state.cpp index d319c23..2a18104 100644 --- a/bt/bt_state.cpp +++ b/bt/bt_state.cpp @@ -12,7 +12,7 @@ #include "bt_state.h" #include "../editor/debugger/limbo_debugger.h" -#include "../util/limbo_def.h" +#include "../util/limbo_compat.h" #include "../util/limbo_string_names.h" #ifdef LIMBOAI_MODULE diff --git a/bt/tasks/bt_task.cpp b/bt/tasks/bt_task.cpp index 1f103b5..4f54317 100644 --- a/bt/tasks/bt_task.cpp +++ b/bt/tasks/bt_task.cpp @@ -382,12 +382,7 @@ void BTTask::print_tree(int p_initial_tabs) { tabs += "--"; } -#ifdef LIMBOAI_MODULE - print_line(vformat("%s Name: %s Instance: %s", tabs, get_task_name(), Ref(this))); -#endif -#ifdef LIMBOAI_GDEXTENSION - UtilityFunctions::print(vformat("%s Name: %s Instance: %s", tabs, get_task_name(), Ref(this))); -#endif + PRINT_LINE(vformat("%s Name: %s Instance: %s", tabs, get_task_name(), Ref(this))); for (int i = 0; i < get_child_count(); i++) { get_child(i)->print_tree(p_initial_tabs + 1); @@ -445,6 +440,7 @@ void BTTask::_bind_methods() { GDVIRTUAL_BIND(_get_configuration_warning); #endif // LIMBOAI_MODULE #ifdef LIMBOAI_GDEXTENSION + // TODO: Until virtual functions are implemented in godot-cpp, we do this. Replace this code when possible. ClassDB::bind_method(D_METHOD("_setup"), &BTTask::_setup); ClassDB::bind_method(D_METHOD("_enter"), &BTTask::_enter); ClassDB::bind_method(D_METHOD("_exit"), &BTTask::_exit); diff --git a/bt/tasks/bt_task.h b/bt/tasks/bt_task.h index a5341cf..11be49b 100644 --- a/bt/tasks/bt_task.h +++ b/bt/tasks/bt_task.h @@ -35,7 +35,7 @@ #ifdef LIMBOAI_GDEXTENSION #include "blackboard/blackboard.h" -#include "util/limbo_def.h" +#include "util/limbo_compat.h" #include "util/limbo_string_names.h" #include "util/limbo_task_db.h" diff --git a/bt/tasks/decorators/bt_cooldown.cpp b/bt/tasks/decorators/bt_cooldown.cpp index 422a528..e877ae1 100644 --- a/bt/tasks/decorators/bt_cooldown.cpp +++ b/bt/tasks/decorators/bt_cooldown.cpp @@ -85,7 +85,7 @@ void BTCooldown::_chill() { SceneTree *st = (SceneTree *)Engine::get_singleton()->get_main_loop(); timer = st->create_timer(duration, process_pause); #endif - timer->connect("timeout", callable_mp(this, &BTCooldown::_on_timeout), CONNECT_ONE_SHOT); + timer->connect(LSNAME(timeout), callable_mp(this, &BTCooldown::_on_timeout), CONNECT_ONE_SHOT); } } diff --git a/editor/action_banner.cpp b/editor/action_banner.cpp index a5769fe..99e9051 100644 --- a/editor/action_banner.cpp +++ b/editor/action_banner.cpp @@ -16,12 +16,12 @@ #endif // LIMBOAI_MODULE #ifdef LIMBOAI_GDEXTENSION -#include "../util/limbo_def.h" +#include "../util/limbo_compat.h" #include "../util/limbo_string_names.h" #include -#endif // LIMBOAI_GDEXTENSION +#endif // ! LIMBOAI_GDEXTENSION void ActionBanner::set_text(const String &p_text) { message->set_text(p_text); @@ -67,6 +67,7 @@ void ActionBanner::_notification(int p_what) { } void ActionBanner::_bind_methods() { + ClassDB::bind_method(D_METHOD("_execute_action", "p_action", "p_auto_close"), &ActionBanner::_execute_action); } ActionBanner::ActionBanner() { diff --git a/editor/action_banner.h b/editor/action_banner.h index cdb5c53..70f8c6e 100644 --- a/editor/action_banner.h +++ b/editor/action_banner.h @@ -18,7 +18,7 @@ #include "scene/gui/label.h" #include "scene/gui/margin_container.h" #include "scene/gui/texture_rect.h" -#endif // LIMBOAI_MODULE +#endif // ! LIMBOAI_MODULE #ifdef LIMBOAI_GDEXTENSION #include @@ -27,7 +27,7 @@ #include using namespace godot; -#endif // LIMBOAI_GDEXTENSION +#endif // ! LIMBOAI_GDEXTENSION class ActionBanner : public MarginContainer { GDCLASS(ActionBanner, MarginContainer); @@ -55,4 +55,4 @@ public: ActionBanner(); }; -#endif // ACTION_BANNER \ No newline at end of file +#endif // ! ACTION_BANNER \ No newline at end of file diff --git a/editor/debugger/behavior_tree_view.cpp b/editor/debugger/behavior_tree_view.cpp index 55e3340..05c80c1 100644 --- a/editor/debugger/behavior_tree_view.cpp +++ b/editor/debugger/behavior_tree_view.cpp @@ -14,6 +14,7 @@ #include "behavior_tree_view.h" #include "../../bt/tasks/bt_task.h" +#include "../../util/limbo_compat.h" #include "../../util/limbo_utility.h" #include "behavior_tree_data.h" @@ -27,6 +28,11 @@ #include "scene/resources/style_box.h" #endif // LIMBOAI_MODULE +#ifdef LIMBOAI_GDEXTENSION +#include + +#endif // LIMBOAI_GDEXTENSION + void BehaviorTreeView::_draw_running_status(Object *p_obj, Rect2 p_rect) { p_rect = p_rect.grow_side(SIDE_LEFT, p_rect.get_position().x); theme_cache.sbf_running->draw(tree->get_canvas_item(), p_rect); @@ -167,6 +173,9 @@ void BehaviorTreeView::_do_update_theme_item_cache() { void BehaviorTreeView::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_READY: { + tree->connect(LSNAME(item_collapsed), callable_mp(this, &BehaviorTreeView::_item_collapsed)); + } break; case NOTIFICATION_POSTINITIALIZE: case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: case NOTIFICATION_TRANSLATION_CHANGED: @@ -192,7 +201,6 @@ BehaviorTreeView::BehaviorTreeView() { tree->set_column_expand(2, false); tree->set_anchor(SIDE_RIGHT, ANCHOR_END); tree->set_anchor(SIDE_BOTTOM, ANCHOR_END); - tree->connect(LSNAME(item_collapsed), callable_mp(this, &BehaviorTreeView::_item_collapsed)); } #endif // TOOLS_ENABLED diff --git a/editor/debugger/limbo_debugger.cpp b/editor/debugger/limbo_debugger.cpp index 001b170..901c41e 100644 --- a/editor/debugger/limbo_debugger.cpp +++ b/editor/debugger/limbo_debugger.cpp @@ -129,7 +129,7 @@ void LimboDebugger::_track_tree(NodePath p_path) { _untrack_tree(); } - Node *node = GET_SCENE_TREE()->get_root()->get_node_or_null(p_path); + Node *node = SCENE_TREE()->get_root()->get_node_or_null(p_path); ERR_FAIL_COND(node == nullptr); tracked_player = p_path; @@ -164,7 +164,7 @@ void LimboDebugger::_untrack_tree() { NodePath was_tracking = tracked_player; tracked_player = NodePath(); - Node *node = GET_SCENE_TREE()->get_root()->get_node_or_null(was_tracking); + Node *node = SCENE_TREE()->get_root()->get_node_or_null(was_tracking); ERR_FAIL_COND(node == nullptr); if (node->is_class("BTPlayer")) { diff --git a/editor/limbo_ai_editor_plugin.cpp b/editor/limbo_ai_editor_plugin.cpp index 8f8a6ce..b164928 100644 --- a/editor/limbo_ai_editor_plugin.cpp +++ b/editor/limbo_ai_editor_plugin.cpp @@ -13,16 +13,18 @@ #include "limbo_ai_editor_plugin.h" +#include "../bt/behavior_tree.h" +#include "../bt/tasks/bt_comment.h" +#include "../bt/tasks/composites/bt_probability_selector.h" +#include "../bt/tasks/composites/bt_selector.h" +#include "../bt/tasks/decorators/bt_subtree.h" +#include "../util/limbo_compat.h" +// #include "../editor/debugger/limbo_debugger_plugin.h" // TODO: reenable when debugger is ready. +#include "../editor/editor_property_bb_param.h" +#include "../util/limbo_utility.h" #include "action_banner.h" -#include "modules/limboai/bt/behavior_tree.h" -#include "modules/limboai/bt/tasks/bt_comment.h" -#include "modules/limboai/bt/tasks/composites/bt_probability_selector.h" -#include "modules/limboai/bt/tasks/composites/bt_selector.h" -#include "modules/limboai/bt/tasks/decorators/bt_subtree.h" -#include "modules/limboai/editor/debugger/limbo_debugger_plugin.h" -#include "modules/limboai/editor/editor_property_bb_param.h" -#include "modules/limboai/util/limbo_utility.h" +#ifdef LIMBOAI_MODULE #include "core/config/project_settings.h" #include "core/error/error_macros.h" #include "core/input/input.h" @@ -39,6 +41,31 @@ #include "editor/project_settings_editor.h" #include "scene/gui/panel_container.h" #include "scene/gui/separator.h" +#endif // ! LIMBOAI_MODULE + +#ifdef LIMBOAI_GDEXTENSION +#include "godot_cpp/classes/editor_interface.hpp" +#include "godot_cpp/classes/editor_paths.hpp" +#include "godot_cpp/classes/ref_counted.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // ! LIMBOAI_GDEXTENSION //**** LimboAIEditor @@ -53,7 +80,7 @@ void LimboAIEditor::_add_task(const Ref &p_task) { } ERR_FAIL_COND(p_task.is_null()); - EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); + EditorUndoRedoManager *undo_redo = GET_UNDO_REDO(); undo_redo->create_action(TTR("Add BT Task")); int insert_idx = -1; @@ -66,19 +93,19 @@ void LimboAIEditor::_add_task(const Ref &p_task) { } if (parent.is_null()) { // When tree is empty. - undo_redo->add_do_method(task_tree->get_bt().ptr(), SNAME("set_root_task"), p_task); - undo_redo->add_undo_method(task_tree->get_bt().ptr(), SNAME("set_root_task"), task_tree->get_bt()->get_root_task()); + undo_redo->add_do_method(task_tree->get_bt().ptr(), LSNAME(set_root_task), p_task); + undo_redo->add_undo_method(task_tree->get_bt().ptr(), LSNAME(set_root_task), task_tree->get_bt()->get_root_task()); } else { - if (Input::get_singleton()->is_key_pressed(Key::SHIFT) && selected->get_parent().is_valid()) { + if (Input::get_singleton()->is_key_pressed(LW_KEY(SHIFT)) && selected->get_parent().is_valid()) { // When shift is pressed, insert task after the currently selected and on the same level. parent = selected->get_parent(); insert_idx = selected->get_index() + 1; } - undo_redo->add_do_method(parent.ptr(), SNAME("add_child_at_index"), p_task, insert_idx); - undo_redo->add_undo_method(parent.ptr(), SNAME("remove_child"), p_task); + undo_redo->add_do_method(parent.ptr(), LSNAME(add_child_at_index), p_task, insert_idx); + undo_redo->add_undo_method(parent.ptr(), LSNAME(remove_child), p_task); } - undo_redo->add_do_method(task_tree, SNAME("update_tree")); - undo_redo->add_undo_method(task_tree, SNAME("update_tree")); + undo_redo->add_do_method(task_tree, LSNAME(update_tree)); + undo_redo->add_undo_method(task_tree, LSNAME(update_tree)); undo_redo->commit_action(); _mark_as_dirty(true); @@ -88,15 +115,13 @@ Ref LimboAIEditor::_create_task_by_class_or_path(const String &p_class_o Ref ret; if (p_class_or_path.begins_with("res:")) { - Ref