diff --git a/editor/debugger/behavior_tree_data.cpp b/editor/debugger/behavior_tree_data.cpp index 9626bb4..0ec8ef1 100644 --- a/editor/debugger/behavior_tree_data.cpp +++ b/editor/debugger/behavior_tree_data.cpp @@ -25,7 +25,6 @@ Array BehaviorTreeData::serialize(const Ref &p_tree_instance, const Node // Flatten tree into list depth first List> stack; stack.push_back(p_tree_instance); - int id = 0; while (stack.size()) { Ref task = stack[0]; stack.pop_front(); @@ -41,7 +40,7 @@ Array BehaviorTreeData::serialize(const Ref &p_tree_instance, const Node script_path = s->get_path(); } - arr.push_back(id); + arr.push_back(task->get_instance_id()); arr.push_back(task->get_task_name()); arr.push_back(!task->get_custom_name().is_empty()); arr.push_back(num_children); @@ -49,8 +48,6 @@ Array BehaviorTreeData::serialize(const Ref &p_tree_instance, const Node arr.push_back(task->get_elapsed_time()); arr.push_back(task->get_class()); arr.push_back(script_path); - - id += 1; } return arr; @@ -89,7 +86,6 @@ Ref BehaviorTreeData::create_from_tree_instance(const Ref> stack; stack.push_back(p_tree_instance); - int id = 0; while (stack.size()) { Ref task = stack[0]; stack.pop_front(); @@ -106,7 +102,7 @@ Ref BehaviorTreeData::create_from_tree_instance(const Reftasks.push_back(TaskData( - id, + task->get_instance_id(), task->get_task_name(), !task->get_custom_name().is_empty(), num_children, @@ -114,7 +110,6 @@ Ref BehaviorTreeData::create_from_tree_instance(const Refget_elapsed_time(), task->get_class(), script_path)); - id += 1; } return data; } diff --git a/editor/debugger/behavior_tree_data.h b/editor/debugger/behavior_tree_data.h index e5c2335..0d5ee9e 100644 --- a/editor/debugger/behavior_tree_data.h +++ b/editor/debugger/behavior_tree_data.h @@ -22,7 +22,7 @@ protected: public: struct TaskData { - int id = 0; + uint64_t id = 0; String name; bool is_custom_name = false; int num_children = 0; @@ -31,7 +31,7 @@ public: String type_name; String script_path; - TaskData(int p_id, const String &p_name, bool p_is_custom_name, int p_num_children, int p_status, double p_elapsed_time, const String &p_type_name, const String &p_script_path) { + TaskData(uint64_t p_id, const String &p_name, bool p_is_custom_name, int p_num_children, int p_status, double p_elapsed_time, const String &p_type_name, const String &p_script_path) { id = p_id; name = p_name; is_custom_name = p_is_custom_name; diff --git a/editor/debugger/behavior_tree_view.cpp b/editor/debugger/behavior_tree_view.cpp index e98a557..b8601b3 100644 --- a/editor/debugger/behavior_tree_view.cpp +++ b/editor/debugger/behavior_tree_view.cpp @@ -52,7 +52,7 @@ void BehaviorTreeView::_item_collapsed(Object *p_obj) { if (!item) { return; } - int id = item->get_metadata(0); + uint64_t id = item->get_metadata(0); bool collapsed = item->is_collapsed(); if (!collapsed_ids.has(id) && collapsed) { collapsed_ids.push_back(item->get_metadata(0)); @@ -69,70 +69,131 @@ double BehaviorTreeView::_get_editor_scale() const { } } +inline void _item_set_elapsed_time(TreeItem *p_item, double p_elapsed) { + p_item->set_text(2, rtos(Math::snapped(p_elapsed, 0.01)).pad_decimals(2)); +} + void BehaviorTreeView::update_tree(const Ref &p_data) { // Remember selected. - int selected_id = -1; + uint64_t selected_id = 0; if (tree->get_selected()) { selected_id = tree->get_selected()->get_metadata(0); } - tree->clear(); - TreeItem *parent = nullptr; - List> parents; - for (const BehaviorTreeData::TaskData &task_data : p_data->tasks) { - // Figure out parent. - parent = nullptr; - if (parents.size()) { - Pair &p = parents[0]; - parent = p.first; - if (!(--p.second)) { - // No children left, remove it. - parents.pop_front(); + if (last_root_id != 0 && p_data->tasks.size() > 0 && last_root_id == (uint64_t)p_data->tasks[0].id) { + // * Update tree. + // ! Update routine is built on assumption that the behavior tree does NOT mutate. With little work it could detect mutations. + + TreeItem *item = tree->get_root(); + int idx = 0; + while (item) { + ERR_FAIL_COND(idx >= p_data->tasks.size()); + + const BTTask::Status current_status = (BTTask::Status)p_data->tasks[idx].status; + const BTTask::Status last_status = VariantCaster::cast(item->get_metadata(1)); + const bool status_changed = last_status != p_data->tasks[idx].status; + + if (status_changed) { + item->set_metadata(1, current_status); + if (current_status == BTTask::SUCCESS) { + item->set_custom_draw(0, this, LW_NAME(_draw_success_status)); + item->set_icon(1, theme_cache.icon_success); + } else if (current_status == BTTask::FAILURE) { + item->set_custom_draw(0, this, LW_NAME(_draw_failure_status)); + item->set_icon(1, theme_cache.icon_failure); + } else if (current_status == BTTask::RUNNING) { + item->set_custom_draw(0, this, LW_NAME(_draw_running_status)); + item->set_icon(1, theme_cache.icon_running); + } else { + item->set_custom_draw(0, this, LW_NAME(_draw_fresh)); + item->set_icon(1, nullptr); + } + } + + if (status_changed || current_status == BTTask::RUNNING) { + _item_set_elapsed_time(item, p_data->tasks[idx].elapsed_time); + } + + if (item->get_first_child()) { + item = item->get_first_child(); + } else if (item->get_next()) { + item = item->get_next(); + } else { + while (item) { + item = item->get_parent(); + if (item && item->get_next()) { + item = item->get_next(); + break; + } + } + } + + idx += 1; + } + ERR_FAIL_COND(idx != p_data->tasks.size()); + } else { + // * Create new tree. + + tree->clear(); + TreeItem *parent = nullptr; + List> parents; + for (const BehaviorTreeData::TaskData &task_data : p_data->tasks) { + // Figure out parent. + parent = nullptr; + if (parents.size()) { + Pair &p = parents[0]; + parent = p.first; + if (!(--p.second)) { + // No children left, remove it. + parents.pop_front(); + } + } + + TreeItem *item = tree->create_item(parent); + // Do this first because it resets properties of the cell... + item->set_cell_mode(0, TreeItem::CELL_MODE_CUSTOM); + item->set_cell_mode(1, TreeItem::CELL_MODE_ICON); + + item->set_metadata(0, task_data.id); + item->set_metadata(1, task_data.status); + + item->set_text(0, task_data.name); + if (task_data.is_custom_name) { + item->set_custom_font(0, theme_cache.font_custom_name); + } + + item->set_text_alignment(2, HORIZONTAL_ALIGNMENT_RIGHT); + _item_set_elapsed_time(item, task_data.elapsed_time); + + String cors = (task_data.script_path.is_empty()) ? task_data.type_name : task_data.script_path; + item->set_icon(0, LimboUtility::get_singleton()->get_task_icon(cors)); + item->set_icon_max_width(0, 16 * _get_editor_scale()); // Force user icon size. + + if (task_data.status == BTTask::SUCCESS) { + item->set_custom_draw(0, this, LW_NAME(_draw_success_status)); + item->set_icon(1, theme_cache.icon_success); + } else if (task_data.status == BTTask::FAILURE) { + item->set_custom_draw(0, this, LW_NAME(_draw_failure_status)); + item->set_icon(1, theme_cache.icon_failure); + } else if (task_data.status == BTTask::RUNNING) { + item->set_custom_draw(0, this, LW_NAME(_draw_running_status)); + item->set_icon(1, theme_cache.icon_running); + } + + if (task_data.id == selected_id) { + tree->set_selected(item, 0); + } + + if (collapsed_ids.has(task_data.id)) { + item->set_collapsed(true); + } + + // Add in front of parents stack if children are expected. + if (task_data.num_children) { + parents.push_front(Pair(item, task_data.num_children)); } } - - TreeItem *item = tree->create_item(parent); - // Do this first because it resets properties of the cell... - item->set_cell_mode(0, TreeItem::CELL_MODE_CUSTOM); - item->set_cell_mode(1, TreeItem::CELL_MODE_ICON); - - item->set_metadata(0, task_data.id); - - item->set_text(0, task_data.name); - if (task_data.is_custom_name) { - item->set_custom_font(0, theme_cache.font_custom_name); - } - - item->set_text_alignment(2, HORIZONTAL_ALIGNMENT_RIGHT); - item->set_text(2, rtos(Math::snapped(task_data.elapsed_time, 0.01)).pad_decimals(2)); - - String cors = (task_data.script_path.is_empty()) ? task_data.type_name : task_data.script_path; - item->set_icon(0, LimboUtility::get_singleton()->get_task_icon(cors)); - item->set_icon_max_width(0, 16 * _get_editor_scale()); // Force user icon size. - - if (task_data.status == BTTask::SUCCESS) { - item->set_custom_draw(0, this, LW_NAME(_draw_success_status)); - item->set_icon(1, theme_cache.icon_success); - } else if (task_data.status == BTTask::FAILURE) { - item->set_custom_draw(0, this, LW_NAME(_draw_failure_status)); - item->set_icon(1, theme_cache.icon_failure); - } else if (task_data.status == BTTask::RUNNING) { - item->set_custom_draw(0, this, LW_NAME(_draw_running_status)); - item->set_icon(1, theme_cache.icon_running); - } - - if (task_data.id == selected_id) { - tree->set_selected(item, 0); - } - - if (collapsed_ids.has(task_data.id)) { - item->set_collapsed(true); - } - - // Add in front of parents stack if it expects children. - if (task_data.num_children) { - parents.push_front(Pair(item, task_data.num_children)); - } + last_root_id = p_data->tasks.size() > 0 ? p_data->tasks[0].id : 0; } } diff --git a/editor/debugger/behavior_tree_view.h b/editor/debugger/behavior_tree_view.h index 49205f7..af183d2 100644 --- a/editor/debugger/behavior_tree_view.h +++ b/editor/debugger/behavior_tree_view.h @@ -48,11 +48,13 @@ private: Ref font_custom_name; } theme_cache; - Vector collapsed_ids; + Vector collapsed_ids; + uint64_t last_root_id = 0; void _draw_success_status(Object *p_obj, Rect2 p_rect); void _draw_running_status(Object *p_obj, Rect2 p_rect); void _draw_failure_status(Object *p_obj, Rect2 p_rect); + void _draw_fresh(Object *p_obj, Rect2 p_rect) {} void _item_collapsed(Object *p_obj); double _get_editor_scale() const; diff --git a/util/limbo_string_names.cpp b/util/limbo_string_names.cpp index 097e008..6dd6092 100644 --- a/util/limbo_string_names.cpp +++ b/util/limbo_string_names.cpp @@ -28,6 +28,7 @@ LimboStringNames *LimboStringNames::singleton = nullptr; LimboStringNames::LimboStringNames() { _draw_failure_status = SN("_draw_failure_status"); + _draw_fresh = SN("_draw_fresh"); _draw_probability = SN("_draw_probability"); _draw_running_status = SN("_draw_running_status"); _draw_success_status = SN("_draw_success_status"); diff --git a/util/limbo_string_names.h b/util/limbo_string_names.h index 35aeace..6111c0a 100644 --- a/util/limbo_string_names.h +++ b/util/limbo_string_names.h @@ -42,6 +42,7 @@ public: _FORCE_INLINE_ static LimboStringNames *get_singleton() { return singleton; } StringName _draw_failure_status; + StringName _draw_fresh; StringName _draw_probability; StringName _draw_running_status; StringName _draw_success_status;