Debugger: Add node filter and improve UX
This commit is contained in:
parent
c362001ed4
commit
4e0305de51
|
@ -5,7 +5,9 @@
|
|||
|
||||
//// BehaviorTreeData
|
||||
|
||||
BehaviorTreeData::BehaviorTreeData(const Ref<BTTask> &p_instance) {
|
||||
BehaviorTreeData::BehaviorTreeData(const Ref<BTTask> &p_instance, const NodePath &p_player_path) {
|
||||
bt_player_path = p_player_path;
|
||||
|
||||
// Flatten tree into list depth first
|
||||
List<Ref<BTTask>> stack;
|
||||
stack.push_back(p_instance);
|
||||
|
@ -31,6 +33,7 @@ BehaviorTreeData::BehaviorTreeData(const Ref<BTTask> &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);
|
||||
|
|
|
@ -31,11 +31,12 @@ public:
|
|||
};
|
||||
|
||||
List<TaskData> tasks;
|
||||
NodePath bt_player_path;
|
||||
|
||||
void serialize(Array &p_arr);
|
||||
void deserialize(const Array &p_arr);
|
||||
|
||||
BehaviorTreeData(const Ref<BTTask> &p_instance);
|
||||
BehaviorTreeData(const Ref<BTTask> &p_instance, const NodePath &p_player_path);
|
||||
BehaviorTreeData() {}
|
||||
};
|
||||
|
||||
|
|
|
@ -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<BTTask> 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<BTTask> 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<BTTask> 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<NodePath, Ref<BTTask>> 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<String> &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]);
|
||||
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_list->set_item_text_direction(i, TEXT_DIRECTION_RTL);
|
||||
if (p_node_paths[i] == selected_bt) {
|
||||
select_idx = i;
|
||||
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<EditorDebuggerSession> p_session) {
|
||||
|
@ -83,39 +124,49 @@ LimboDebuggerTab::LimboDebuggerTab(Ref<EditorDebuggerSession> 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);
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
alert_message = memnew(Label);
|
||||
alert_box->add_child(alert_message);
|
||||
alert_message->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
|
||||
|
||||
info_message = memnew(Label);
|
||||
info_box->add_child(info_message);
|
||||
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);
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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<String> active_bt_players;
|
||||
Ref<EditorDebuggerSession> 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<String> &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<EditorDebuggerSession> p_session);
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue