diff --git a/debugger/behavior_tree_data.cpp b/debugger/behavior_tree_data.cpp index cbb8f2d..381ea22 100644 --- a/debugger/behavior_tree_data.cpp +++ b/debugger/behavior_tree_data.cpp @@ -5,7 +5,9 @@ //// BehaviorTreeData -BehaviorTreeData::BehaviorTreeData(const Ref &p_instance) { +BehaviorTreeData::BehaviorTreeData(const Ref &p_instance, const NodePath &p_player_path) { + bt_player_path = p_player_path; + // Flatten tree into list depth first List> stack; stack.push_back(p_instance); @@ -31,6 +33,7 @@ BehaviorTreeData::BehaviorTreeData(const Ref &p_instance) { } void BehaviorTreeData::serialize(Array &p_arr) { + p_arr.push_back(bt_player_path); for (const TaskData &td : tasks) { p_arr.push_back(td.id); p_arr.push_back(td.name); @@ -43,10 +46,12 @@ void BehaviorTreeData::serialize(Array &p_arr) { void BehaviorTreeData::deserialize(const Array &p_arr) { ERR_FAIL_COND(tasks.size() != 0); - - int idx = 0; - while (p_arr.size() > idx) { - ERR_FAIL_COND(p_arr.size() < 6); + ERR_FAIL_COND(p_arr.size() < 1); + ERR_FAIL_COND(p_arr[0].get_type() != Variant::NODE_PATH); + bt_player_path = p_arr[0]; + int idx = 1; + while (p_arr.size() > idx + 1) { + ERR_FAIL_COND(p_arr.size() < idx + 6); ERR_FAIL_COND(p_arr[idx].get_type() != Variant::INT); ERR_FAIL_COND(p_arr[idx + 1].get_type() != Variant::STRING); ERR_FAIL_COND(p_arr[idx + 2].get_type() != Variant::INT); diff --git a/debugger/behavior_tree_data.h b/debugger/behavior_tree_data.h index 88957e3..8261027 100644 --- a/debugger/behavior_tree_data.h +++ b/debugger/behavior_tree_data.h @@ -31,11 +31,12 @@ public: }; List tasks; + NodePath bt_player_path; void serialize(Array &p_arr); void deserialize(const Array &p_arr); - BehaviorTreeData(const Ref &p_instance); + BehaviorTreeData(const Ref &p_instance, const NodePath &p_player_path); BehaviorTreeData() {} }; diff --git a/debugger/limbo_debugger.cpp b/debugger/limbo_debugger.cpp index 673000d..d833046 100644 --- a/debugger/limbo_debugger.cpp +++ b/debugger/limbo_debugger.cpp @@ -42,13 +42,13 @@ void LimboDebugger::deinitialize() { #ifdef DEBUG_ENABLED Error LimboDebugger::parse_message(void *p_user, const String &p_msg, const Array &p_args, bool &r_captured) { r_captured = true; - if (p_msg == "track_bt_updates") { + if (p_msg == "track_bt_player") { singleton->_track_tree(p_args[0]); - } else if (p_msg == "untrack_bt_updates") { - // unregister bt for updates + } else if (p_msg == "untrack_bt_player") { + singleton->_untrack_tree(); } else if (p_msg == "start_session") { singleton->session_active = true; - singleton->_send_active_behavior_trees(); + singleton->_send_active_bt_players(); } else if (p_msg == "stop_session") { singleton->session_active = false; } else { @@ -62,11 +62,12 @@ void LimboDebugger::register_bt_instance(Ref p_instance, NodePath p_path active_trees.insert(p_path, p_instance); if (session_active) { - _send_active_behavior_trees(); + _send_active_bt_players(); } } void LimboDebugger::unregister_bt_instance(Ref p_instance, NodePath p_path) { + ERR_FAIL_COND(p_path.is_empty()); ERR_FAIL_COND(!active_trees.has(p_path)); if (tracked_tree == p_path) { @@ -75,7 +76,7 @@ void LimboDebugger::unregister_bt_instance(Ref p_instance, NodePath p_pa active_trees.erase(p_path); if (session_active) { - _send_active_behavior_trees(); + _send_active_bt_players(); } } @@ -115,12 +116,12 @@ void LimboDebugger::_untrack_tree() { } } -void LimboDebugger::_send_active_behavior_trees() { +void LimboDebugger::_send_active_bt_players() { Array arr; for (KeyValue> kv : active_trees) { arr.append(kv.key); } - EngineDebugger::get_singleton()->send_message("limboai:active_behavior_trees", arr); + EngineDebugger::get_singleton()->send_message("limboai:active_bt_players", arr); } void LimboDebugger::_on_bt_updated(int _status, NodePath p_path) { @@ -128,7 +129,7 @@ void LimboDebugger::_on_bt_updated(int _status, NodePath p_path) { return; } Array arr; - BehaviorTreeData(active_trees.get(tracked_tree)).serialize(arr); + BehaviorTreeData(active_trees.get(tracked_tree), tracked_tree).serialize(arr); EngineDebugger::get_singleton()->send_message("limboai:bt_update", arr); } @@ -137,7 +138,7 @@ void LimboDebugger::_on_state_updated(float _delta, NodePath p_path) { return; } Array arr; - BehaviorTreeData(active_trees.get(tracked_tree)).serialize(arr); + BehaviorTreeData(active_trees.get(tracked_tree), tracked_tree).serialize(arr); EngineDebugger::get_singleton()->send_message("limboai:bt_update", arr); } diff --git a/debugger/limbo_debugger.h b/debugger/limbo_debugger.h index b4d0bd3..1c2e09c 100644 --- a/debugger/limbo_debugger.h +++ b/debugger/limbo_debugger.h @@ -31,7 +31,7 @@ private: void _track_tree(NodePath p_path); void _untrack_tree(); - void _send_active_behavior_trees(); + void _send_active_bt_players(); void _on_bt_updated(int status, NodePath p_path); void _on_state_updated(float _delta, NodePath p_path); diff --git a/debugger/limbo_debugger_plugin.cpp b/debugger/limbo_debugger_plugin.cpp index 1c00bba..02ca56b 100644 --- a/debugger/limbo_debugger_plugin.cpp +++ b/debugger/limbo_debugger_plugin.cpp @@ -16,65 +16,106 @@ #include "scene/gui/control.h" #include "scene/gui/item_list.h" #include "scene/gui/label.h" +#include "scene/gui/line_edit.h" #include "scene/gui/split_container.h" #include "scene/gui/texture_rect.h" /////////////////////// LimboDebuggerTab void LimboDebuggerTab::start_session() { - bt_list->clear(); + bt_player_list->clear(); bt_view->clear(); - info_box->hide(); - hsc->show(); - message->hide(); + alert_box->hide(); + info_message->set_text(TTR("Pick a player from the list to display behavior tree.")); + info_message->show(); session->send_message("limboai:start_session", Array()); } void LimboDebuggerTab::stop_session() { - hsc->hide(); - message->show(); + bt_player_list->clear(); + bt_view->clear(); + alert_box->hide(); + info_message->set_text(TTR("Run project to start debugging.")); + info_message->show(); session->send_message("limboai:stop_session", Array()); } -void LimboDebuggerTab::update_bt_list(const Array &p_node_paths) { +void LimboDebuggerTab::update_active_bt_players(const Array &p_node_paths) { + active_bt_players.clear(); + for (int i = 0; i < p_node_paths.size(); i++) { + active_bt_players.push_back(p_node_paths[i]); + } + _update_bt_player_list(active_bt_players, filter_players->get_text()); +} + +String LimboDebuggerTab::get_selected_bt_player() { + if (!bt_player_list->is_anything_selected()) { + return ""; + } + return bt_player_list->get_item_text(bt_player_list->get_selected_items()[0]); +} + +void LimboDebuggerTab::update_behavior_tree(const BehaviorTreeData &p_data) { + bt_view->update_tree(p_data); + info_message->hide(); +} + +void LimboDebuggerTab::_show_alert(const String &p_message) { + alert_message->set_text(p_message); + alert_icon->set_texture(get_theme_icon(SNAME("NodeInfo"), SNAME("EditorIcons"))); + alert_box->set_visible(!p_message.is_empty()); +} + +void LimboDebuggerTab::_update_bt_player_list(const List &p_node_paths, const String &p_filter) { // Remember selected item. - String selected_bt = ""; - if (bt_list->is_anything_selected()) { - selected_bt = bt_list->get_item_text(bt_list->get_selected_items().get(0)); + String selected_player = ""; + if (bt_player_list->is_anything_selected()) { + selected_player = bt_player_list->get_item_text(bt_player_list->get_selected_items().get(0)); } - bt_list->clear(); + bt_player_list->clear(); int select_idx = -1; - for (int i = 0; i < p_node_paths.size(); i++) { - bt_list->add_item(p_node_paths[i]); - // Make item text shortened from the left, e.g ".../Agent/BTPlayer". - bt_list->set_item_text_direction(i, TEXT_DIRECTION_RTL); - if (p_node_paths[i] == selected_bt) { - select_idx = i; + bool selection_filtered_out = false; + for (const String &p : p_node_paths) { + if (p_filter.is_empty() || p.contains(p_filter)) { + int idx = bt_player_list->add_item(p); + // Make item text shortened from the left, e.g ".../Agent/BTPlayer". + bt_player_list->set_item_text_direction(idx, TEXT_DIRECTION_RTL); + if (p == selected_player) { + select_idx = idx; + } + } else if (p == selected_player) { + selection_filtered_out = true; } } // Restore selected item. if (select_idx > -1) { - bt_list->select(select_idx); - } else if (!selected_bt.is_empty()) { - _set_info_message(TTR("Node instance is gone")); + bt_player_list->select(select_idx); + } else if (!selected_player.is_empty()) { + if (selection_filtered_out) { + session->send_message("limboai:untrack_bt_player", Array()); + bt_view->clear(); + _show_alert(""); + } else { + _show_alert("BehaviorTree player is no longer present."); + } } } -void LimboDebuggerTab::_set_info_message(const String &p_message) { - info_message->set_text(p_message); - info_icon->set_texture(get_theme_icon(SNAME("NodeInfo"), SNAME("EditorIcons"))); - info_box->set_visible(!p_message.is_empty()); -} - void LimboDebuggerTab::_bt_selected(int p_idx) { - info_box->hide(); + alert_box->hide(); bt_view->clear(); - NodePath path = bt_list->get_item_text(p_idx); + info_message->set_text(TTR("Waiting for behavior tree update.")); + info_message->show(); + NodePath path = bt_player_list->get_item_text(p_idx); Array data; data.push_back(path); - session->send_message("limboai:track_bt_updates", data); + session->send_message("limboai:track_bt_player", data); +} + +void LimboDebuggerTab::_filter_changed(String p_text) { + _update_bt_player_list(active_bt_players, p_text); } LimboDebuggerTab::LimboDebuggerTab(Ref p_session) { @@ -83,39 +124,49 @@ LimboDebuggerTab::LimboDebuggerTab(Ref p_session) { hsc = memnew(HSplitContainer); add_child(hsc); - bt_list = memnew(ItemList); - hsc->add_child(bt_list); - bt_list->set_custom_minimum_size(Size2(240.0 * EDSCALE, 0.0)); - bt_list->connect(SNAME("item_selected"), callable_mp(this, &LimboDebuggerTab::_bt_selected)); + VBoxContainer *list_box = memnew(VBoxContainer); + hsc->add_child(list_box); + + filter_players = memnew(LineEdit); + filter_players->set_placeholder(TTR("Filter Players")); + filter_players->connect(SNAME("text_changed"), callable_mp(this, &LimboDebuggerTab::_filter_changed)); + list_box->add_child(filter_players); + + bt_player_list = memnew(ItemList); + bt_player_list->set_custom_minimum_size(Size2(240.0 * EDSCALE, 0.0)); + bt_player_list->set_h_size_flags(SIZE_FILL); + bt_player_list->set_v_size_flags(SIZE_EXPAND_FILL); + bt_player_list->connect(SNAME("item_selected"), callable_mp(this, &LimboDebuggerTab::_bt_selected)); + list_box->add_child(bt_player_list); view_box = memnew(VBoxContainer); - { - hsc->add_child(view_box); + hsc->add_child(view_box); - bt_view = memnew(BehaviorTreeView); - view_box->add_child(bt_view); - bt_view->set_h_size_flags(Control::SIZE_EXPAND_FILL); - bt_view->set_v_size_flags(Control::SIZE_EXPAND_FILL); + bt_view = memnew(BehaviorTreeView); + bt_view->set_h_size_flags(Control::SIZE_EXPAND_FILL); + bt_view->set_v_size_flags(Control::SIZE_EXPAND_FILL); + view_box->add_child(bt_view); - info_box = memnew(HBoxContainer); - view_box->add_child(info_box); - info_box->hide(); + alert_box = memnew(HBoxContainer); + alert_box->hide(); + view_box->add_child(alert_box); - info_icon = memnew(TextureRect); - info_box->add_child(info_icon); - info_icon->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED); + alert_icon = memnew(TextureRect); + alert_box->add_child(alert_icon); + alert_icon->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED); - info_message = memnew(Label); - info_box->add_child(info_message); - info_message->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); - } + alert_message = memnew(Label); + alert_box->add_child(alert_message); + alert_message->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); - message = memnew(Label); - add_child(message); - message->set_text(TTR("Run project to start debugging")); - message->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); - message->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); - message->set_anchors_preset(Control::PRESET_CENTER); + info_message = memnew(Label); + info_message->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); + info_message->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); + info_message->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); + info_message->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); + info_message->set_anchors_and_offsets_preset(PRESET_FULL_RECT, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE); + + bt_view->add_child(info_message); stop_session(); } @@ -133,12 +184,14 @@ void LimboDebuggerPlugin::setup_session(int p_idx) { bool LimboDebuggerPlugin::capture(const String &p_message, const Array &p_data, int p_session) { bool captured = true; - if (p_message == "limboai:active_behavior_trees") { - tab->update_bt_list(p_data); + if (p_message == "limboai:active_bt_players") { + tab->update_active_bt_players(p_data); } else if (p_message == "limboai:bt_update") { BehaviorTreeData data = BehaviorTreeData(); data.deserialize(p_data); - tab->get_behavior_tree_view()->update_tree(data); + if (data.bt_player_path == tab->get_selected_bt_player()) { + tab->update_behavior_tree(data); + } } else { captured = false; } @@ -151,4 +204,4 @@ bool LimboDebuggerPlugin::has_capture(const String &p_capture) const { LimboDebuggerPlugin::LimboDebuggerPlugin() { tab = nullptr; -} \ No newline at end of file +} diff --git a/debugger/limbo_debugger_plugin.h b/debugger/limbo_debugger_plugin.h index cd2f10a..9e075dd 100644 --- a/debugger/limbo_debugger_plugin.h +++ b/debugger/limbo_debugger_plugin.h @@ -7,6 +7,7 @@ #include "core/object/object.h" #include "core/typedefs.h" #include "editor/plugins/editor_debugger_plugin.h" +#include "modules/limboai/debugger/behavior_tree_data.h" #include "modules/limboai/debugger/behavior_tree_view.h" #include "scene/gui/box_container.h" #include "scene/gui/item_list.h" @@ -18,24 +19,30 @@ class LimboDebuggerTab : public PanelContainer { GDCLASS(LimboDebuggerTab, PanelContainer); private: + List active_bt_players; Ref session; HSplitContainer *hsc; - Label *message; - ItemList *bt_list; + Label *info_message; + ItemList *bt_player_list; BehaviorTreeView *bt_view; VBoxContainer *view_box; - HBoxContainer *info_box; - TextureRect *info_icon; - Label *info_message; + HBoxContainer *alert_box; + TextureRect *alert_icon; + Label *alert_message; + LineEdit *filter_players; - void _set_info_message(const String &p_message); + void _show_alert(const String &p_message); + void _update_bt_player_list(const List &p_node_paths, const String &p_filter); void _bt_selected(int p_idx); + void _filter_changed(String p_text); public: void start_session(); void stop_session(); - void update_bt_list(const Array &p_node_paths); + void update_active_bt_players(const Array &p_node_paths); BehaviorTreeView *get_behavior_tree_view() const { return bt_view; } + String get_selected_bt_player(); + void update_behavior_tree(const BehaviorTreeData &p_data); LimboDebuggerTab(Ref p_session); };