Debugger: Add the resource header control with a path to the BehaviorTree for the currently debugged instance.

This commit is contained in:
Serhii Snitsaruk 2023-12-12 23:37:28 +01:00
parent a3594e173c
commit fb8585282d
6 changed files with 102 additions and 52 deletions

View File

@ -16,8 +16,50 @@
//// BehaviorTreeData
BehaviorTreeData::BehaviorTreeData(const Ref<BTTask> &p_instance, const NodePath &p_player_path) {
void BehaviorTreeData::serialize(Array &p_arr) {
p_arr.push_back(bt_player_path);
p_arr.push_back(bt_resource_path);
for (const TaskData &td : tasks) {
p_arr.push_back(td.id);
p_arr.push_back(td.name);
p_arr.push_back(td.is_custom_name);
p_arr.push_back(td.num_children);
p_arr.push_back(td.status);
p_arr.push_back(td.elapsed_time);
p_arr.push_back(td.type_name);
p_arr.push_back(td.script_path);
}
}
void BehaviorTreeData::deserialize(const Array &p_arr) {
ERR_FAIL_COND(tasks.size() != 0);
ERR_FAIL_COND(p_arr.size() < 2);
ERR_FAIL_COND(p_arr[0].get_type() != Variant::NODE_PATH);
bt_player_path = p_arr[0];
ERR_FAIL_COND(p_arr[1].get_type() != Variant::STRING);
bt_resource_path = p_arr[1];
int idx = 2;
while (p_arr.size() > idx + 1) {
ERR_FAIL_COND(p_arr.size() < idx + 7);
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::BOOL);
ERR_FAIL_COND(p_arr[idx + 3].get_type() != Variant::INT);
ERR_FAIL_COND(p_arr[idx + 4].get_type() != Variant::INT);
ERR_FAIL_COND(p_arr[idx + 5].get_type() != Variant::FLOAT);
ERR_FAIL_COND(p_arr[idx + 6].get_type() != Variant::STRING);
ERR_FAIL_COND(p_arr[idx + 7].get_type() != Variant::STRING);
tasks.push_back(TaskData(p_arr[idx], p_arr[idx + 1], p_arr[idx + 2], p_arr[idx + 3], p_arr[idx + 4], p_arr[idx + 5], p_arr[idx + 6], p_arr[idx + 7]));
idx += 8;
}
}
BehaviorTreeData::BehaviorTreeData(const Ref<BTTask> &p_instance, const NodePath &p_player_path, const String &p_bt_resource) {
bt_player_path = p_player_path;
bt_resource_path = p_bt_resource;
// Flatten tree into list depth first
List<Ref<BTTask>> stack;
@ -50,40 +92,3 @@ BehaviorTreeData::BehaviorTreeData(const Ref<BTTask> &p_instance, const NodePath
id += 1;
}
}
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);
p_arr.push_back(td.is_custom_name);
p_arr.push_back(td.num_children);
p_arr.push_back(td.status);
p_arr.push_back(td.elapsed_time);
p_arr.push_back(td.type_name);
p_arr.push_back(td.script_path);
}
}
void BehaviorTreeData::deserialize(const Array &p_arr) {
ERR_FAIL_COND(tasks.size() != 0);
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 + 7);
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::BOOL);
ERR_FAIL_COND(p_arr[idx + 3].get_type() != Variant::INT);
ERR_FAIL_COND(p_arr[idx + 4].get_type() != Variant::INT);
ERR_FAIL_COND(p_arr[idx + 5].get_type() != Variant::FLOAT);
ERR_FAIL_COND(p_arr[idx + 6].get_type() != Variant::STRING);
ERR_FAIL_COND(p_arr[idx + 7].get_type() != Variant::STRING);
tasks.push_back(TaskData(p_arr[idx], p_arr[idx + 1], p_arr[idx + 2], p_arr[idx + 3], p_arr[idx + 4], p_arr[idx + 5], p_arr[idx + 6], p_arr[idx + 7]));
idx += 8;
}
}

View File

@ -42,11 +42,12 @@ public:
List<TaskData> tasks;
NodePath bt_player_path;
String bt_resource_path;
void serialize(Array &p_arr);
void deserialize(const Array &p_arr);
BehaviorTreeData(const Ref<BTTask> &p_instance, const NodePath &p_player_path);
BehaviorTreeData(const Ref<BTTask> &p_instance, const NodePath &p_player_path, const String &p_bt_resource);
BehaviorTreeData() {}
};

View File

@ -16,6 +16,7 @@
#include "core/debugger/engine_debugger.h"
#include "core/error/error_macros.h"
#include "core/io/resource.h"
#include "core/string/node_path.h"
#include "scene/main/scene_tree.h"
#include "scene/main/window.h"
@ -86,7 +87,7 @@ void LimboDebugger::unregister_bt_instance(Ref<BTTask> p_instance, NodePath p_pl
ERR_FAIL_COND(p_player_path.is_empty());
ERR_FAIL_COND(!active_trees.has(p_player_path));
if (tracked_tree == p_player_path) {
if (tracked_player == p_player_path) {
_untrack_tree();
}
active_trees.erase(p_player_path);
@ -99,14 +100,23 @@ void LimboDebugger::unregister_bt_instance(Ref<BTTask> p_instance, NodePath p_pl
void LimboDebugger::_track_tree(NodePath p_path) {
ERR_FAIL_COND(!active_trees.has(p_path));
if (!tracked_tree.is_empty()) {
if (!tracked_player.is_empty()) {
_untrack_tree();
}
Node *node = SceneTree::get_singleton()->get_root()->get_node(p_path);
ERR_FAIL_COND(node == nullptr);
tracked_tree = p_path;
tracked_player = p_path;
bool r_valid = false;
Ref<Resource> bt = node->get(SNAME("behavior_tree"), &r_valid);
if (bt.is_valid()) {
bt_resource_path = bt->get_path();
} else {
bt_resource_path = "";
}
if (node->is_class("BTPlayer")) {
node->connect(SNAME("updated"), callable_mp(this, &LimboDebugger::_on_bt_updated).bind(p_path));
} else if (node->is_class("BTState")) {
@ -115,12 +125,12 @@ void LimboDebugger::_track_tree(NodePath p_path) {
}
void LimboDebugger::_untrack_tree() {
if (tracked_tree.is_empty()) {
if (tracked_player.is_empty()) {
return;
}
NodePath was_tracking = tracked_tree;
tracked_tree = NodePath();
NodePath was_tracking = tracked_player;
tracked_player = NodePath();
Node *node = SceneTree::get_singleton()->get_root()->get_node(was_tracking);
ERR_FAIL_COND(node == nullptr);
@ -141,20 +151,20 @@ void LimboDebugger::_send_active_bt_players() {
}
void LimboDebugger::_on_bt_updated(int _status, NodePath p_path) {
if (p_path != tracked_tree) {
if (p_path != tracked_player) {
return;
}
Array arr;
BehaviorTreeData(active_trees.get(tracked_tree), tracked_tree).serialize(arr);
BehaviorTreeData(active_trees.get(tracked_player), tracked_player, bt_resource_path).serialize(arr);
EngineDebugger::get_singleton()->send_message("limboai:bt_update", arr);
}
void LimboDebugger::_on_state_updated(float _delta, NodePath p_path) {
if (p_path != tracked_tree) {
if (p_path != tracked_player) {
return;
}
Array arr;
BehaviorTreeData(active_trees.get(tracked_tree), tracked_tree).serialize(arr);
BehaviorTreeData(active_trees.get(tracked_player), tracked_player, bt_resource_path).serialize(arr);
EngineDebugger::get_singleton()->send_message("limboai:bt_update", arr);
}

View File

@ -36,7 +36,8 @@ public:
#ifdef DEBUG_ENABLED
private:
HashMap<NodePath, Ref<BTTask>> active_trees;
NodePath tracked_tree;
NodePath tracked_player;
String bt_resource_path;
bool session_active = false;
void _track_tree(NodePath p_path);

View File

@ -14,17 +14,21 @@
#include "limbo_debugger_plugin.h"
#include "limbo_debugger.h"
#include "modules/limboai/bt/behavior_tree.h"
#include "modules/limboai/editor/debugger/behavior_tree_data.h"
#include "modules/limboai/editor/debugger/behavior_tree_view.h"
#include "core/debugger/engine_debugger.h"
#include "core/error/error_macros.h"
#include "core/math/math_defs.h"
#include "core/object/callable_method_pointer.h"
#include "core/os/memory.h"
#include "core/string/print_string.h"
#include "core/string/ustring.h"
#include "core/variant/array.h"
#include "editor/editor_interface.h"
#include "editor/editor_scale.h"
#include "editor/filesystem_dock.h"
#include "editor/plugins/editor_debugger_plugin.h"
#include "scene/gui/box_container.h"
#include "scene/gui/control.h"
@ -52,6 +56,8 @@ void LimboDebuggerTab::stop_session() {
alert_box->hide();
info_message->set_text(TTR("Run project to start debugging."));
info_message->show();
resource_header->set_disabled(true);
resource_header->set_text(TTR("Inactive"));
session->send_message("limboai:stop_session", Array());
}
@ -71,6 +77,8 @@ String LimboDebuggerTab::get_selected_bt_player() {
}
void LimboDebuggerTab::update_behavior_tree(const BehaviorTreeData &p_data) {
resource_header->set_text(p_data.bt_resource_path);
resource_header->set_disabled(false);
bt_view->update_tree(p_data);
info_message->hide();
}
@ -122,6 +130,8 @@ void LimboDebuggerTab::_bt_selected(int p_idx) {
bt_view->clear();
info_message->set_text(TTR("Waiting for behavior tree update."));
info_message->show();
resource_header->set_text(TTR("Waiting for data"));
resource_header->set_disabled(true);
NodePath path = bt_player_list->get_item_text(p_idx);
Array msg_data;
msg_data.push_back(path);
@ -136,9 +146,21 @@ void LimboDebuggerTab::_window_visibility_changed(bool p_visible) {
make_floating->set_visible(!p_visible);
}
void LimboDebuggerTab::_resource_header_pressed() {
String bt_path = resource_header->get_text();
if (bt_path.is_empty()) {
return;
}
FileSystemDock::get_singleton()->select_file(bt_path);
Ref<BehaviorTree> bt = ResourceLoader::load(bt_path, "BehaviorTree");
ERR_FAIL_COND_MSG(!bt.is_valid(), "Failed to load BehaviorTree. Wrong resource path?");
EditorInterface::get_singleton()->edit_resource(bt);
}
void LimboDebuggerTab::_notification(int p_what) {
if (p_what == NOTIFICATION_THEME_CHANGED) {
alert_icon->set_texture(get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")));
alert_icon->set_texture(get_editor_theme_icon(SNAME("StatusWarning")));
resource_header->set_icon(get_editor_theme_icon(SNAME("BehaviorTree")));
}
}
@ -152,6 +174,16 @@ LimboDebuggerTab::LimboDebuggerTab(Ref<EditorDebuggerSession> p_session, WindowW
toolbar = memnew(HBoxContainer);
root_vb->add_child(toolbar);
resource_header = memnew(Button);
toolbar->add_child(resource_header);
resource_header->set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT);
resource_header->set_focus_mode(FOCUS_NONE);
resource_header->add_theme_constant_override("hseparation", 8);
resource_header->set_text(TTR("Inactive"));
resource_header->set_tooltip_text(TTR("Debugged BehaviorTree resource.\nClick to open."));
resource_header->set_disabled(true);
resource_header->connect("pressed", callable_mp(this, &LimboDebuggerTab::_resource_header_pressed));
hsc = memnew(HSplitContainer);
hsc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
hsc->set_v_size_flags(Control::SIZE_EXPAND_FILL);

View File

@ -45,7 +45,7 @@ private:
TextureRect *alert_icon = nullptr;
Label *alert_message = nullptr;
LineEdit *filter_players = nullptr;
Button *resource_header = nullptr;
Button *make_floating = nullptr;
WindowWrapper *window_wrapper = nullptr;
@ -54,6 +54,7 @@ private:
void _bt_selected(int p_idx);
void _filter_changed(String p_text);
void _window_visibility_changed(bool p_visible);
void _resource_header_pressed();
protected:
void _notification(int p_what);