Browse Source

Various fixes and style nitpicks

Mikael Hermansson 3 months ago
parent
commit
3528e83ff3
27 changed files with 529 additions and 833 deletions
  1. 2 1
      core/object/object.cpp
  2. 0 130
      editor/editor_json_visualizer.cpp
  3. 0 51
      editor/editor_json_visualizer.h
  4. 81 6
      editor/shader/editor_native_shader_source_visualizer.cpp
  5. 3 1
      editor/shader/editor_native_shader_source_visualizer.h
  6. 55 47
      modules/objectdb_profiler/editor/data_viewers/class_view.cpp
  7. 2 1
      modules/objectdb_profiler/editor/data_viewers/class_view.h
  8. 0 163
      modules/objectdb_profiler/editor/data_viewers/json_view.cpp
  9. 0 58
      modules/objectdb_profiler/editor/data_viewers/json_view.h
  10. 86 73
      modules/objectdb_profiler/editor/data_viewers/node_view.cpp
  11. 12 11
      modules/objectdb_profiler/editor/data_viewers/node_view.h
  12. 30 21
      modules/objectdb_profiler/editor/data_viewers/object_view.cpp
  13. 51 38
      modules/objectdb_profiler/editor/data_viewers/refcounted_view.cpp
  14. 8 16
      modules/objectdb_profiler/editor/data_viewers/shared_controls.cpp
  15. 2 2
      modules/objectdb_profiler/editor/data_viewers/snapshot_view.cpp
  16. 1 1
      modules/objectdb_profiler/editor/data_viewers/snapshot_view.h
  17. 29 27
      modules/objectdb_profiler/editor/data_viewers/summary_view.cpp
  18. 100 81
      modules/objectdb_profiler/editor/objectdb_profiler_panel.cpp
  19. 6 6
      modules/objectdb_profiler/editor/objectdb_profiler_panel.h
  20. 2 2
      modules/objectdb_profiler/editor/objectdb_profiler_plugin.cpp
  21. 1 1
      modules/objectdb_profiler/editor/objectdb_profiler_plugin.h
  22. 20 34
      modules/objectdb_profiler/editor/snapshot_data.cpp
  23. 4 4
      modules/objectdb_profiler/editor/snapshot_data.h
  24. 8 19
      modules/objectdb_profiler/register_types.cpp
  25. 24 33
      modules/objectdb_profiler/snapshot_collector.cpp
  26. 2 1
      modules/objectdb_profiler/snapshot_collector.h
  27. 0 5
      scene/gui/tree.cpp

+ 2 - 1
core/object/object.cpp

@@ -2336,6 +2336,7 @@ void postinitialize_handler(Object *p_object) {
 
 
 void ObjectDB::debug_objects(DebugFunc p_func, void *p_user_data) {
 void ObjectDB::debug_objects(DebugFunc p_func, void *p_user_data) {
 	spin_lock.lock();
 	spin_lock.lock();
+
 	for (uint32_t i = 0, count = slot_count; i < slot_max && count != 0; i++) {
 	for (uint32_t i = 0, count = slot_count; i < slot_max && count != 0; i++) {
 		if (object_slots[i].validator) {
 		if (object_slots[i].validator) {
 			p_func(object_slots[i].object, p_user_data);
 			p_func(object_slots[i].object, p_user_data);
@@ -2507,7 +2508,7 @@ void ObjectDB::cleanup() {
 						extra_info = " - Resource path: " + String(resource_get_path->call(obj, nullptr, 0, call_error));
 						extra_info = " - Resource path: " + String(resource_get_path->call(obj, nullptr, 0, call_error));
 					}
 					}
 					if (obj->is_class("RefCounted")) {
 					if (obj->is_class("RefCounted")) {
-						extra_info = " - RefCount: " + itos(((RefCounted *)obj)->get_reference_count());
+						extra_info = " - Reference count: " + itos((static_cast<RefCounted *>(obj))->get_reference_count());
 					}
 					}
 
 
 					uint64_t id = uint64_t(i) | (uint64_t(object_slots[i].validator) << OBJECTDB_SLOT_MAX_COUNT_BITS) | (object_slots[i].is_ref_counted ? OBJECTDB_REFERENCE_BIT : 0);
 					uint64_t id = uint64_t(i) | (uint64_t(object_slots[i].validator) << OBJECTDB_SLOT_MAX_COUNT_BITS) | (object_slots[i].is_ref_counted ? OBJECTDB_REFERENCE_BIT : 0);

+ 0 - 130
editor/editor_json_visualizer.cpp

@@ -1,130 +0,0 @@
-/**************************************************************************/
-/*  editor_json_visualizer.cpp                                            */
-/**************************************************************************/
-/*                         This file is part of:                          */
-/*                             GODOT ENGINE                               */
-/*                        https://godotengine.org                         */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
-/*                                                                        */
-/* Permission is hereby granted, free of charge, to any person obtaining  */
-/* a copy of this software and associated documentation files (the        */
-/* "Software"), to deal in the Software without restriction, including    */
-/* without limitation the rights to use, copy, modify, merge, publish,    */
-/* distribute, sublicense, and/or sell copies of the Software, and to     */
-/* permit persons to whom the Software is furnished to do so, subject to  */
-/* the following conditions:                                              */
-/*                                                                        */
-/* The above copyright notice and this permission notice shall be         */
-/* included in all copies or substantial portions of the Software.        */
-/*                                                                        */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
-/**************************************************************************/
-
-#include "editor_json_visualizer.h"
-
-#include "editor/editor_settings.h"
-#include "editor/editor_string_names.h"
-#include "editor/themes/editor_scale.h"
-#include "scene/gui/text_edit.h"
-#include "servers/rendering/shader_language.h"
-
-EditorJsonVisualizerSyntaxHighlighter::EditorJsonVisualizerSyntaxHighlighter(const List<String> &p_keywords) {
-	set_number_color(EDITOR_GET("text_editor/theme/highlighting/number_color"));
-	set_symbol_color(EDITOR_GET("text_editor/theme/highlighting/symbol_color"));
-	set_function_color(EDITOR_GET("text_editor/theme/highlighting/function_color"));
-	set_member_variable_color(EDITOR_GET("text_editor/theme/highlighting/member_variable_color"));
-
-	clear_keyword_colors();
-	const Color keyword_color = EDITOR_GET("text_editor/theme/highlighting/keyword_color");
-	const Color control_flow_keyword_color = EDITOR_GET("text_editor/theme/highlighting/control_flow_keyword_color");
-
-	for (const String &keyword : p_keywords) {
-		if (ShaderLanguage::is_control_flow_keyword(keyword)) {
-			add_keyword_color(keyword, control_flow_keyword_color);
-		} else {
-			add_keyword_color(keyword, keyword_color);
-		}
-	}
-
-	// Colorize comments.
-	const Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color");
-	clear_color_regions();
-	add_color_region("/*", "*/", comment_color, false);
-	add_color_region("//", "", comment_color, true);
-
-	// Colorize preprocessor statements.
-	const Color user_type_color = EDITOR_GET("text_editor/theme/highlighting/user_type_color");
-	add_color_region("#", "", user_type_color, true);
-
-	set_uint_suffix_enabled(true);
-}
-
-void EditorJsonVisualizer::load_theme(Ref<EditorJsonVisualizerSyntaxHighlighter> p_syntax_highlighter) {
-	set_editable(false);
-	set_syntax_highlighter(p_syntax_highlighter);
-	add_theme_font_override(SceneStringName(font), get_theme_font("source", EditorStringName(EditorFonts)));
-	add_theme_font_size_override(SceneStringName(font_size), get_theme_font_size("source_size", EditorStringName(EditorFonts)));
-	add_theme_constant_override("line_spacing", EDITOR_GET("text_editor/appearance/whitespace/line_spacing"));
-
-	// Appearance: Caret
-	set_caret_type((TextEdit::CaretType)EDITOR_GET("text_editor/appearance/caret/type").operator int());
-	set_caret_blink_enabled(EDITOR_GET("text_editor/appearance/caret/caret_blink"));
-	set_caret_blink_interval(EDITOR_GET("text_editor/appearance/caret/caret_blink_interval"));
-	set_highlight_current_line(EDITOR_GET("text_editor/appearance/caret/highlight_current_line"));
-	set_highlight_all_occurrences(EDITOR_GET("text_editor/appearance/caret/highlight_all_occurrences"));
-
-	// Appearance: Gutters
-	set_draw_line_numbers(EDITOR_GET("text_editor/appearance/gutters/show_line_numbers"));
-	set_line_numbers_zero_padded(EDITOR_GET("text_editor/appearance/gutters/line_numbers_zero_padded"));
-
-	// Appearance: Minimap
-	set_draw_minimap(EDITOR_GET("text_editor/appearance/minimap/show_minimap"));
-	set_minimap_width((int)EDITOR_GET("text_editor/appearance/minimap/minimap_width") * EDSCALE);
-
-	// Appearance: Lines
-	set_line_folding_enabled(EDITOR_GET("text_editor/appearance/lines/code_folding"));
-	set_draw_fold_gutter(EDITOR_GET("text_editor/appearance/lines/code_folding"));
-	set_line_wrapping_mode((TextEdit::LineWrappingMode)EDITOR_GET("text_editor/appearance/lines/word_wrap").operator int());
-	set_autowrap_mode((TextServer::AutowrapMode)EDITOR_GET("text_editor/appearance/lines/autowrap_mode").operator int());
-
-	// Appearance: Whitespace
-	set_draw_tabs(EDITOR_GET("text_editor/appearance/whitespace/draw_tabs"));
-	set_draw_spaces(EDITOR_GET("text_editor/appearance/whitespace/draw_spaces"));
-	add_theme_constant_override("line_spacing", EDITOR_GET("text_editor/appearance/whitespace/line_spacing"));
-
-	// Behavior: Navigation
-	set_scroll_past_end_of_file_enabled(EDITOR_GET("text_editor/behavior/navigation/scroll_past_end_of_file"));
-	set_smooth_scroll_enabled(EDITOR_GET("text_editor/behavior/navigation/smooth_scrolling"));
-	set_v_scroll_speed(EDITOR_GET("text_editor/behavior/navigation/v_scroll_speed"));
-	set_drag_and_drop_selection_enabled(EDITOR_GET("text_editor/behavior/navigation/drag_and_drop_selection"));
-
-	// Behavior: Indent
-	set_indent_size(EDITOR_GET("text_editor/behavior/indent/size"));
-	set_auto_indent_enabled(EDITOR_GET("text_editor/behavior/indent/auto_indent"));
-	set_indent_wrapped_lines(EDITOR_GET("text_editor/behavior/indent/indent_wrapped_lines"));
-}
-
-void EditorJsonVisualizer::_notification(int p_what) {
-	if (p_what == NOTIFICATION_THEME_CHANGED) {
-		Ref<Font> source_font = get_theme_font("source", EditorStringName(EditorFonts));
-		int source_font_size = get_theme_font_size("source_size", EditorStringName(EditorFonts));
-		int line_spacing = EDITOR_GET("text_editor/theme/line_spacing");
-		if (get_theme_font(SceneStringName(font)) != source_font) {
-			add_theme_font_override(SceneStringName(font), source_font);
-		}
-		if (get_theme_font_size(SceneStringName(font_size)) != source_font_size) {
-			add_theme_font_size_override(SceneStringName(font_size), source_font_size);
-		}
-		if (get_theme_constant("line_spacing") != line_spacing) {
-			add_theme_constant_override("line_spacing", line_spacing);
-		}
-	}
-}

+ 0 - 51
editor/editor_json_visualizer.h

@@ -1,51 +0,0 @@
-/**************************************************************************/
-/*  editor_json_visualizer.h                                              */
-/**************************************************************************/
-/*                         This file is part of:                          */
-/*                             GODOT ENGINE                               */
-/*                        https://godotengine.org                         */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
-/*                                                                        */
-/* Permission is hereby granted, free of charge, to any person obtaining  */
-/* a copy of this software and associated documentation files (the        */
-/* "Software"), to deal in the Software without restriction, including    */
-/* without limitation the rights to use, copy, modify, merge, publish,    */
-/* distribute, sublicense, and/or sell copies of the Software, and to     */
-/* permit persons to whom the Software is furnished to do so, subject to  */
-/* the following conditions:                                              */
-/*                                                                        */
-/* The above copyright notice and this permission notice shall be         */
-/* included in all copies or substantial portions of the Software.        */
-/*                                                                        */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
-/**************************************************************************/
-
-#pragma once
-
-#include "scene/gui/code_edit.h"
-#include "scene/resources/syntax_highlighter.h"
-
-class EditorJsonVisualizerSyntaxHighlighter : public CodeHighlighter {
-	GDCLASS(EditorJsonVisualizerSyntaxHighlighter, CodeHighlighter)
-
-public:
-	EditorJsonVisualizerSyntaxHighlighter(const List<String> &p_keywords);
-};
-
-class EditorJsonVisualizer : public CodeEdit {
-	GDCLASS(EditorJsonVisualizer, CodeEdit)
-
-protected:
-	void _notification(int p_what);
-
-public:
-	void load_theme(Ref<EditorJsonVisualizerSyntaxHighlighter> p_syntax_highlighter);
-};

+ 81 - 6
editor/shader/editor_native_shader_source_visualizer.cpp

@@ -37,6 +37,40 @@
 #include "scene/gui/text_edit.h"
 #include "scene/gui/text_edit.h"
 #include "servers/rendering/shader_language.h"
 #include "servers/rendering/shader_language.h"
 
 
+void EditorNativeShaderSourceVisualizer::_load_theme_settings() {
+	syntax_highlighter->set_number_color(EDITOR_GET("text_editor/theme/highlighting/number_color"));
+	syntax_highlighter->set_symbol_color(EDITOR_GET("text_editor/theme/highlighting/symbol_color"));
+	syntax_highlighter->set_function_color(EDITOR_GET("text_editor/theme/highlighting/function_color"));
+	syntax_highlighter->set_member_variable_color(EDITOR_GET("text_editor/theme/highlighting/member_variable_color"));
+
+	syntax_highlighter->clear_keyword_colors();
+
+	List<String> keywords;
+	ShaderLanguage::get_keyword_list(&keywords);
+	const Color keyword_color = EDITOR_GET("text_editor/theme/highlighting/keyword_color");
+	const Color control_flow_keyword_color = EDITOR_GET("text_editor/theme/highlighting/control_flow_keyword_color");
+
+	for (const String &keyword : keywords) {
+		if (ShaderLanguage::is_control_flow_keyword(keyword)) {
+			syntax_highlighter->add_keyword_color(keyword, control_flow_keyword_color);
+		} else {
+			syntax_highlighter->add_keyword_color(keyword, keyword_color);
+		}
+	}
+
+	// Colorize comments.
+	const Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color");
+	syntax_highlighter->clear_color_regions();
+	syntax_highlighter->add_color_region("/*", "*/", comment_color, false);
+	syntax_highlighter->add_color_region("//", "", comment_color, true);
+
+	// Colorize preprocessor statements.
+	const Color user_type_color = EDITOR_GET("text_editor/theme/highlighting/user_type_color");
+	syntax_highlighter->add_color_region("#", "", user_type_color, true);
+
+	syntax_highlighter->set_uint_suffix_enabled(true);
+}
+
 void EditorNativeShaderSourceVisualizer::_inspect_shader(RID p_shader) {
 void EditorNativeShaderSourceVisualizer::_inspect_shader(RID p_shader) {
 	if (versions) {
 	if (versions) {
 		memdelete(versions);
 		memdelete(versions);
@@ -45,10 +79,7 @@ void EditorNativeShaderSourceVisualizer::_inspect_shader(RID p_shader) {
 
 
 	RS::ShaderNativeSourceCode nsc = RS::get_singleton()->shader_get_native_source_code(p_shader);
 	RS::ShaderNativeSourceCode nsc = RS::get_singleton()->shader_get_native_source_code(p_shader);
 
 
-	List<String> keywords;
-	ShaderLanguage::get_keyword_list(&keywords);
-	Ref<EditorJsonVisualizerSyntaxHighlighter> syntax_highlighter;
-	syntax_highlighter.instantiate(keywords);
+	_load_theme_settings();
 
 
 	versions = memnew(TabContainer);
 	versions = memnew(TabContainer);
 	versions->set_tab_alignment(TabBar::ALIGNMENT_CENTER);
 	versions->set_tab_alignment(TabBar::ALIGNMENT_CENTER);
@@ -62,8 +93,50 @@ void EditorNativeShaderSourceVisualizer::_inspect_shader(RID p_shader) {
 		vtab->set_h_size_flags(Control::SIZE_EXPAND_FILL);
 		vtab->set_h_size_flags(Control::SIZE_EXPAND_FILL);
 		versions->add_child(vtab);
 		versions->add_child(vtab);
 		for (int j = 0; j < nsc.versions[i].stages.size(); j++) {
 		for (int j = 0; j < nsc.versions[i].stages.size(); j++) {
-			EditorJsonVisualizer *code_edit = memnew(EditorJsonVisualizer);
-			code_edit->load_theme(syntax_highlighter);
+			CodeEdit *code_edit = memnew(CodeEdit);
+			code_edit->set_editable(false);
+			code_edit->set_syntax_highlighter(syntax_highlighter);
+			code_edit->add_theme_font_override(SceneStringName(font), get_theme_font("source", EditorStringName(EditorFonts)));
+			code_edit->add_theme_font_size_override(SceneStringName(font_size), get_theme_font_size("source_size", EditorStringName(EditorFonts)));
+			code_edit->add_theme_constant_override("line_spacing", EDITOR_GET("text_editor/appearance/whitespace/line_spacing"));
+
+			// Appearance: Caret
+			code_edit->set_caret_type((TextEdit::CaretType)EDITOR_GET("text_editor/appearance/caret/type").operator int());
+			code_edit->set_caret_blink_enabled(EDITOR_GET("text_editor/appearance/caret/caret_blink"));
+			code_edit->set_caret_blink_interval(EDITOR_GET("text_editor/appearance/caret/caret_blink_interval"));
+			code_edit->set_highlight_current_line(EDITOR_GET("text_editor/appearance/caret/highlight_current_line"));
+			code_edit->set_highlight_all_occurrences(EDITOR_GET("text_editor/appearance/caret/highlight_all_occurrences"));
+
+			// Appearance: Gutters
+			code_edit->set_draw_line_numbers(EDITOR_GET("text_editor/appearance/gutters/show_line_numbers"));
+			code_edit->set_line_numbers_zero_padded(EDITOR_GET("text_editor/appearance/gutters/line_numbers_zero_padded"));
+
+			// Appearance: Minimap
+			code_edit->set_draw_minimap(EDITOR_GET("text_editor/appearance/minimap/show_minimap"));
+			code_edit->set_minimap_width((int)EDITOR_GET("text_editor/appearance/minimap/minimap_width") * EDSCALE);
+
+			// Appearance: Lines
+			code_edit->set_line_folding_enabled(EDITOR_GET("text_editor/appearance/lines/code_folding"));
+			code_edit->set_draw_fold_gutter(EDITOR_GET("text_editor/appearance/lines/code_folding"));
+			code_edit->set_line_wrapping_mode((TextEdit::LineWrappingMode)EDITOR_GET("text_editor/appearance/lines/word_wrap").operator int());
+			code_edit->set_autowrap_mode((TextServer::AutowrapMode)EDITOR_GET("text_editor/appearance/lines/autowrap_mode").operator int());
+
+			// Appearance: Whitespace
+			code_edit->set_draw_tabs(EDITOR_GET("text_editor/appearance/whitespace/draw_tabs"));
+			code_edit->set_draw_spaces(EDITOR_GET("text_editor/appearance/whitespace/draw_spaces"));
+			code_edit->add_theme_constant_override("line_spacing", EDITOR_GET("text_editor/appearance/whitespace/line_spacing"));
+
+			// Behavior: Navigation
+			code_edit->set_scroll_past_end_of_file_enabled(EDITOR_GET("text_editor/behavior/navigation/scroll_past_end_of_file"));
+			code_edit->set_smooth_scroll_enabled(EDITOR_GET("text_editor/behavior/navigation/smooth_scrolling"));
+			code_edit->set_v_scroll_speed(EDITOR_GET("text_editor/behavior/navigation/v_scroll_speed"));
+			code_edit->set_drag_and_drop_selection_enabled(EDITOR_GET("text_editor/behavior/navigation/drag_and_drop_selection"));
+
+			// Behavior: Indent
+			code_edit->set_indent_size(EDITOR_GET("text_editor/behavior/indent/size"));
+			code_edit->set_auto_indent_enabled(EDITOR_GET("text_editor/behavior/indent/auto_indent"));
+			code_edit->set_indent_wrapped_lines(EDITOR_GET("text_editor/behavior/indent/indent_wrapped_lines"));
+
 			code_edit->set_name(nsc.versions[i].stages[j].name);
 			code_edit->set_name(nsc.versions[i].stages[j].name);
 			code_edit->set_text(nsc.versions[i].stages[j].code);
 			code_edit->set_text(nsc.versions[i].stages[j].code);
 			code_edit->set_v_size_flags(Control::SIZE_EXPAND_FILL);
 			code_edit->set_v_size_flags(Control::SIZE_EXPAND_FILL);
@@ -80,6 +153,8 @@ void EditorNativeShaderSourceVisualizer::_bind_methods() {
 }
 }
 
 
 EditorNativeShaderSourceVisualizer::EditorNativeShaderSourceVisualizer() {
 EditorNativeShaderSourceVisualizer::EditorNativeShaderSourceVisualizer() {
+	syntax_highlighter.instantiate();
+
 	add_to_group("_native_shader_source_visualizer");
 	add_to_group("_native_shader_source_visualizer");
 	set_title(TTR("Native Shader Source Inspector"));
 	set_title(TTR("Native Shader Source Inspector"));
 }
 }

+ 3 - 1
editor/shader/editor_native_shader_source_visualizer.h

@@ -30,14 +30,16 @@
 
 
 #pragma once
 #pragma once
 
 
-#include "editor/editor_json_visualizer.h"
 #include "scene/gui/dialogs.h"
 #include "scene/gui/dialogs.h"
 #include "scene/gui/tab_container.h"
 #include "scene/gui/tab_container.h"
+#include "scene/resources/syntax_highlighter.h"
 
 
 class EditorNativeShaderSourceVisualizer : public AcceptDialog {
 class EditorNativeShaderSourceVisualizer : public AcceptDialog {
 	GDCLASS(EditorNativeShaderSourceVisualizer, AcceptDialog)
 	GDCLASS(EditorNativeShaderSourceVisualizer, AcceptDialog)
 	TabContainer *versions = nullptr;
 	TabContainer *versions = nullptr;
+	Ref<CodeHighlighter> syntax_highlighter;
 
 
+	void _load_theme_settings();
 	void _inspect_shader(RID p_shader);
 	void _inspect_shader(RID p_shader);
 
 
 protected:
 protected:

+ 55 - 47
modules/objectdb_profiler/editor/data_viewers/class_view.cpp

@@ -57,11 +57,7 @@ int ClassData::get_recursive_instance_count(HashMap<String, ClassData> &p_all_cl
 }
 }
 
 
 SnapshotClassView::SnapshotClassView() {
 SnapshotClassView::SnapshotClassView() {
-	set_name(TTR("Classes"));
-
-	class_tree = nullptr;
-	object_list = nullptr;
-	diff_object_list = nullptr;
+	set_name(TTRC("Classes"));
 }
 }
 
 
 void SnapshotClassView::show_snapshot(GameStateSnapshot *p_data, GameStateSnapshot *p_diff_data) {
 void SnapshotClassView::show_snapshot(GameStateSnapshot *p_data, GameStateSnapshot *p_diff_data) {
@@ -84,45 +80,43 @@ void SnapshotClassView::show_snapshot(GameStateSnapshot *p_data, GameStateSnapsh
 
 
 	class_tree = memnew(Tree);
 	class_tree = memnew(Tree);
 
 
-	TreeSortAndFilterBar *filter_bar = memnew(TreeSortAndFilterBar(class_tree, TTR("Filter Classes")));
-	filter_bar->add_sort_option(TTR("Name"), TreeSortAndFilterBar::SortType::ALPHA_SORT, 0);
+	TreeSortAndFilterBar *filter_bar = memnew(TreeSortAndFilterBar(class_tree, TTRC("Filter Classes")));
+	filter_bar->add_sort_option(TTRC("Name"), TreeSortAndFilterBar::SortType::ALPHA_SORT, 0);
 
 
 	TreeSortAndFilterBar::SortOptionIndexes default_sort;
 	TreeSortAndFilterBar::SortOptionIndexes default_sort;
 	if (!diff_data) {
 	if (!diff_data) {
-		default_sort = filter_bar->add_sort_option(TTR("Count"), TreeSortAndFilterBar::SortType::NUMERIC_SORT, 1);
+		default_sort = filter_bar->add_sort_option(TTRC("Count"), TreeSortAndFilterBar::SortType::NUMERIC_SORT, 1);
 	} else {
 	} else {
-		filter_bar->add_sort_option(TTR("A Count"), TreeSortAndFilterBar::SortType::NUMERIC_SORT, 1);
-		filter_bar->add_sort_option(TTR("B Count"), TreeSortAndFilterBar::SortType::NUMERIC_SORT, 2);
-		default_sort = filter_bar->add_sort_option(TTR("Delta"), TreeSortAndFilterBar::SortType::NUMERIC_SORT, 3);
+		filter_bar->add_sort_option(TTRC("A Count"), TreeSortAndFilterBar::SortType::NUMERIC_SORT, 1);
+		filter_bar->add_sort_option(TTRC("B Count"), TreeSortAndFilterBar::SortType::NUMERIC_SORT, 2);
+		default_sort = filter_bar->add_sort_option(TTRC("Delta"), TreeSortAndFilterBar::SortType::NUMERIC_SORT, 3);
 	}
 	}
 	class_list_column->add_child(filter_bar);
 	class_list_column->add_child(filter_bar);
 
 
 	class_tree->set_select_mode(Tree::SelectMode::SELECT_ROW);
 	class_tree->set_select_mode(Tree::SelectMode::SELECT_ROW);
 	class_tree->set_custom_minimum_size(Size2(200 * EDSCALE, 0));
 	class_tree->set_custom_minimum_size(Size2(200 * EDSCALE, 0));
 	class_tree->set_hide_folding(false);
 	class_tree->set_hide_folding(false);
-	class_list_column->add_child(class_tree);
 	class_tree->set_hide_root(true);
 	class_tree->set_hide_root(true);
 	class_tree->set_columns(diff_data ? 4 : 2);
 	class_tree->set_columns(diff_data ? 4 : 2);
 	class_tree->set_column_titles_visible(true);
 	class_tree->set_column_titles_visible(true);
-	class_tree->set_column_title(0, TTR("Object Class"));
+	class_tree->set_column_title(0, TTRC("Class"));
 	class_tree->set_column_expand(0, true);
 	class_tree->set_column_expand(0, true);
 	class_tree->set_column_custom_minimum_width(0, 200 * EDSCALE);
 	class_tree->set_column_custom_minimum_width(0, 200 * EDSCALE);
-	class_tree->set_column_title(1, diff_data ? TTR("A Count") : TTR("Count"));
+	class_tree->set_column_title(1, diff_data ? TTRC("A Count") : TTRC("Count"));
 	class_tree->set_column_expand(1, false);
 	class_tree->set_column_expand(1, false);
 	if (diff_data) {
 	if (diff_data) {
-		class_tree->set_column_title(2, TTR("B Count"));
+		class_tree->set_column_title_tooltip_text(1, vformat(TTR("A: %s"), snapshot_data->name));
+		class_tree->set_column_title_tooltip_text(2, vformat(TTR("B: %s"), diff_data->name));
+		class_tree->set_column_title(2, TTRC("B Count"));
 		class_tree->set_column_expand(2, false);
 		class_tree->set_column_expand(2, false);
-		class_tree->set_column_title(3, TTR("Delta"));
+		class_tree->set_column_title(3, TTRC("Delta"));
 		class_tree->set_column_expand(3, false);
 		class_tree->set_column_expand(3, false);
-
-		// Add tooltip with the names of snapshot A and B
-		class_tree->set_column_title_tooltip_text(1, TTR("A: ") + snapshot_data->name);
-		class_tree->set_column_title_tooltip_text(2, TTR("B: ") + diff_data->name);
 	}
 	}
 	class_tree->connect(SceneStringName(item_selected), callable_mp(this, &SnapshotClassView::_class_selected));
 	class_tree->connect(SceneStringName(item_selected), callable_mp(this, &SnapshotClassView::_class_selected));
 	class_tree->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 	class_tree->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 	class_tree->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 	class_tree->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 	class_tree->set_anchors_preset(LayoutPreset::PRESET_FULL_RECT);
 	class_tree->set_anchors_preset(LayoutPreset::PRESET_FULL_RECT);
+	class_list_column->add_child(class_tree);
 
 
 	VSplitContainer *object_lists = memnew(VSplitContainer);
 	VSplitContainer *object_lists = memnew(VSplitContainer);
 	classes_view->add_child(object_lists);
 	classes_view->add_child(object_lists);
@@ -130,10 +124,10 @@ void SnapshotClassView::show_snapshot(GameStateSnapshot *p_data, GameStateSnapsh
 	object_lists->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 	object_lists->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 	object_lists->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 	object_lists->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 	if (!diff_data) {
 	if (!diff_data) {
-		object_lists->add_child(object_list = _make_object_list_tree(TTR("Objects")));
+		object_lists->add_child(object_list = _make_object_list_tree(TTRC("Objects")));
 	} else {
 	} else {
-		object_lists->add_child(object_list = _make_object_list_tree(TTR("A Objects")));
-		object_lists->add_child(diff_object_list = _make_object_list_tree(TTR("B Objects")));
+		object_lists->add_child(object_list = _make_object_list_tree(TTRC("A Objects")));
+		object_lists->add_child(diff_object_list = _make_object_list_tree(TTRC("B Objects")));
 	}
 	}
 
 
 	HashMap<String, ClassData> grouped_by_class;
 	HashMap<String, ClassData> grouped_by_class;
@@ -149,12 +143,13 @@ void SnapshotClassView::show_snapshot(GameStateSnapshot *p_data, GameStateSnapsh
 		classes_todo.push_front(c);
 		classes_todo.push_front(c);
 	}
 	}
 	while (classes_todo.size() > 0) {
 	while (classes_todo.size() > 0) {
-		String next_class_name = classes_todo.get(0);
+		String next_class_name = classes_todo.front()->get();
 		classes_todo.pop_front();
 		classes_todo.pop_front();
 		ClassData &next = grouped_by_class[next_class_name];
 		ClassData &next = grouped_by_class[next_class_name];
 		ClassData &nexts_parent = grouped_by_class[next.parent_class_name];
 		ClassData &nexts_parent = grouped_by_class[next.parent_class_name];
 		next.tree_node = class_tree->create_item(nexts_parent.tree_node);
 		next.tree_node = class_tree->create_item(nexts_parent.tree_node);
 		next.tree_node->set_text(0, next_class_name + " (" + String::num_int64(next.instance_count(snapshot_data)) + ")");
 		next.tree_node->set_text(0, next_class_name + " (" + String::num_int64(next.instance_count(snapshot_data)) + ")");
+		next.tree_node->set_auto_translate_mode(0, AUTO_TRANSLATE_MODE_DISABLED);
 		int a_count = next.get_recursive_instance_count(grouped_by_class, snapshot_data);
 		int a_count = next.get_recursive_instance_count(grouped_by_class, snapshot_data);
 		next.tree_node->set_text(1, String::num_int64(a_count));
 		next.tree_node->set_text(1, String::num_int64(a_count));
 		if (diff_data) {
 		if (diff_data) {
@@ -193,13 +188,13 @@ Tree *SnapshotClassView::_make_object_list_tree(const String &p_column_name) {
 
 
 void SnapshotClassView::_add_objects_to_class_map(HashMap<String, ClassData> &p_class_map, GameStateSnapshot *p_objects) {
 void SnapshotClassView::_add_objects_to_class_map(HashMap<String, ClassData> &p_class_map, GameStateSnapshot *p_objects) {
 	for (const KeyValue<ObjectID, SnapshotDataObject *> &pair : p_objects->objects) {
 	for (const KeyValue<ObjectID, SnapshotDataObject *> &pair : p_objects->objects) {
-		StringName class_name = StringName(pair.value->type_name);
-		StringName parent_class_name = class_name != StringName() && ClassDB::class_exists(class_name) ? ClassDB::get_parent_class(class_name) : "";
+		StringName class_name = pair.value->type_name;
+		StringName parent_class_name = !class_name.is_empty() && ClassDB::class_exists(class_name) ? ClassDB::get_parent_class(class_name) : "";
 
 
 		p_class_map[class_name].instances.push_back(pair.value);
 		p_class_map[class_name].instances.push_back(pair.value);
 
 
 		// Go up the tree and insert all parents/grandparents.
 		// Go up the tree and insert all parents/grandparents.
-		while (class_name != StringName()) {
+		while (!class_name.is_empty()) {
 			if (!p_class_map.has(class_name)) {
 			if (!p_class_map.has(class_name)) {
 				p_class_map[class_name] = ClassData(class_name, parent_class_name);
 				p_class_map[class_name] = ClassData(class_name, parent_class_name);
 			}
 			}
@@ -212,7 +207,7 @@ void SnapshotClassView::_add_objects_to_class_map(HashMap<String, ClassData> &p_
 			p_class_map[parent_class_name].child_classes.insert(class_name);
 			p_class_map[parent_class_name].child_classes.insert(class_name);
 
 
 			class_name = parent_class_name;
 			class_name = parent_class_name;
-			parent_class_name = class_name != StringName() ? ClassDB::get_parent_class(class_name) : "";
+			parent_class_name = !class_name.is_empty() ? ClassDB::get_parent_class(class_name) : "";
 		}
 		}
 	}
 	}
 }
 }
@@ -230,45 +225,58 @@ void SnapshotClassView::_object_selected(Tree *p_tree) {
 		}
 		}
 	}
 	}
 	ObjectID object_id = p_tree->get_selected()->get_metadata(0);
 	ObjectID object_id = p_tree->get_selected()->get_metadata(0);
-	EditorNode::get_singleton()->push_item((Object *)snapshot->objects[object_id]);
+	EditorNode::get_singleton()->push_item(static_cast<Object *>(snapshot->objects[object_id]));
 }
 }
 
 
 void SnapshotClassView::_class_selected() {
 void SnapshotClassView::_class_selected() {
-	if (!diff_data) {
-		_populate_object_list(snapshot_data, object_list, TTR("Objects"));
-	} else {
-		_populate_object_list(snapshot_data, object_list, TTR("A Objects"));
-		_populate_object_list(diff_data, diff_object_list, TTR("B Objects"));
-	}
+	_update_lists();
 }
 }
 
 
 void SnapshotClassView::_populate_object_list(GameStateSnapshot *p_snapshot, Tree *p_list, const String &p_name_base) {
 void SnapshotClassView::_populate_object_list(GameStateSnapshot *p_snapshot, Tree *p_list, const String &p_name_base) {
 	p_list->clear();
 	p_list->clear();
-	String class_name = class_tree->get_selected()->get_metadata(0);
+
+	TreeItem *selected_item = class_tree->get_selected();
+	if (selected_item == nullptr) {
+		p_list->set_column_title(0, vformat("%s (0)", TTR(p_name_base)));
+		return;
+	}
+
+	String class_name = selected_item->get_metadata(0);
 	TreeItem *root = p_list->create_item();
 	TreeItem *root = p_list->create_item();
 	int object_count = 0;
 	int object_count = 0;
 	for (const KeyValue<ObjectID, SnapshotDataObject *> &pair : p_snapshot->objects) {
 	for (const KeyValue<ObjectID, SnapshotDataObject *> &pair : p_snapshot->objects) {
 		if (pair.value->type_name == class_name) {
 		if (pair.value->type_name == class_name) {
 			TreeItem *item = p_list->create_item(root);
 			TreeItem *item = p_list->create_item(root);
+			item->set_auto_translate_mode(0, AUTO_TRANSLATE_MODE_DISABLED);
 			item->set_text(0, pair.value->get_name());
 			item->set_text(0, pair.value->get_name());
 			item->set_metadata(0, pair.value->remote_object_id);
 			item->set_metadata(0, pair.value->remote_object_id);
 			item->set_text_overrun_behavior(0, TextServer::OverrunBehavior::OVERRUN_NO_TRIMMING);
 			item->set_text_overrun_behavior(0, TextServer::OverrunBehavior::OVERRUN_NO_TRIMMING);
 			object_count++;
 			object_count++;
 		}
 		}
 	}
 	}
-	p_list->set_column_title(0, p_name_base + " (" + itos(object_count) + ")");
+
+	p_list->set_column_title(0, vformat("%s (%d)", TTR(p_name_base), object_count));
 }
 }
 
 
-void SnapshotClassView::_notification(int p_what) {
-	switch (p_what) {
-		case NOTIFICATION_ENTER_TREE:
-		case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
-		case NOTIFICATION_THEME_CHANGED:
-		case NOTIFICATION_TRANSLATION_CHANGED: {
-			for (TreeItem *item : _get_children_recursive(class_tree)) {
-				item->set_icon(0, EditorNode::get_singleton()->get_class_icon(item->get_metadata(0), ""));
-			}
+void SnapshotClassView::_update_lists() {
+	if (snapshot_data == nullptr) {
+		return;
+	}
+
+	if (!diff_data) {
+		_populate_object_list(snapshot_data, object_list, TTRC("Objects"));
+	} else {
+		_populate_object_list(snapshot_data, object_list, TTRC("A Objects"));
+		_populate_object_list(diff_data, diff_object_list, TTRC("B Objects"));
+	}
+}
 
 
-		} break;
+void SnapshotClassView::_notification(int p_what) {
+	if (p_what == NOTIFICATION_THEME_CHANGED) {
+		for (TreeItem *item : _get_children_recursive(class_tree)) {
+			item->set_icon(0, EditorNode::get_singleton()->get_class_icon(item->get_metadata(0), ""));
+		}
+	} else if (p_what == NOTIFICATION_TRANSLATION_CHANGED) {
+		_update_lists();
 	}
 	}
 }
 }

+ 2 - 1
modules/objectdb_profiler/editor/data_viewers/class_view.h

@@ -43,7 +43,7 @@ struct ClassData {
 	String class_name;
 	String class_name;
 	String parent_class_name;
 	String parent_class_name;
 	HashSet<String> child_classes;
 	HashSet<String> child_classes;
-	List<SnapshotDataObject *> instances;
+	LocalVector<SnapshotDataObject *> instances;
 	TreeItem *tree_node = nullptr;
 	TreeItem *tree_node = nullptr;
 	HashMap<GameStateSnapshot *, int> recursive_instance_count_cache;
 	HashMap<GameStateSnapshot *, int> recursive_instance_count_cache;
 
 
@@ -66,6 +66,7 @@ protected:
 
 
 	Tree *_make_object_list_tree(const String &p_column_name);
 	Tree *_make_object_list_tree(const String &p_column_name);
 	void _populate_object_list(GameStateSnapshot *p_snapshot, Tree *p_list, const String &p_name_base);
 	void _populate_object_list(GameStateSnapshot *p_snapshot, Tree *p_list, const String &p_name_base);
+	void _update_lists();
 
 
 public:
 public:
 	SnapshotClassView();
 	SnapshotClassView();

+ 0 - 163
modules/objectdb_profiler/editor/data_viewers/json_view.cpp

@@ -1,163 +0,0 @@
-/**************************************************************************/
-/*  json_view.cpp                                                         */
-/**************************************************************************/
-/*                         This file is part of:                          */
-/*                             GODOT ENGINE                               */
-/*                        https://godotengine.org                         */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
-/*                                                                        */
-/* Permission is hereby granted, free of charge, to any person obtaining  */
-/* a copy of this software and associated documentation files (the        */
-/* "Software"), to deal in the Software without restriction, including    */
-/* without limitation the rights to use, copy, modify, merge, publish,    */
-/* distribute, sublicense, and/or sell copies of the Software, and to     */
-/* permit persons to whom the Software is furnished to do so, subject to  */
-/* the following conditions:                                              */
-/*                                                                        */
-/* The above copyright notice and this permission notice shall be         */
-/* included in all copies or substantial portions of the Software.        */
-/*                                                                        */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
-/**************************************************************************/
-
-#include "json_view.h"
-
-#include "shared_controls.h"
-
-#include "core/io/json.h"
-#include "scene/gui/center_container.h"
-#include "scene/gui/split_container.h"
-
-SnapshotJsonView::SnapshotJsonView() {
-	set_name(TTR("JSON"));
-}
-
-void SnapshotJsonView::show_snapshot(GameStateSnapshot *p_data, GameStateSnapshot *p_diff_data) {
-	// Lock isn't released until the data processing background thread has finished running
-	// and the json has been passed back to the main thread and displayed.
-	SnapshotView::show_snapshot(p_data, p_diff_data);
-
-	HSplitContainer *box = memnew(HSplitContainer);
-	box->set_anchors_preset(LayoutPreset::PRESET_FULL_RECT);
-	add_child(box);
-
-	loading_panel = memnew(DarkPanelContainer);
-	CenterContainer *loading_center = memnew(CenterContainer);
-	Label *loading_label = memnew(Label(TTR("Loading")));
-	add_child(loading_panel);
-	loading_panel->add_child(loading_center);
-	loading_center->add_child(loading_label);
-	loading_panel->set_anchors_preset(LayoutPreset::PRESET_FULL_RECT);
-	loading_center->set_anchors_preset(LayoutPreset::PRESET_FULL_RECT);
-
-	VBoxContainer *json_box = memnew(VBoxContainer);
-	json_box->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
-	json_box->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
-	box->add_child(json_box);
-	String hdr_a_text = diff_data ? TTR("Snapshot A JSON") : TTR("Snapshot JSON");
-	SpanningHeader *hdr_a = memnew(SpanningHeader(hdr_a_text));
-	if (diff_data) {
-		hdr_a->set_tooltip_text(TTR("Snapshot A:") + " " + snapshot_data->name);
-	}
-	json_box->add_child(hdr_a);
-
-	Ref<EditorJsonVisualizerSyntaxHighlighter> syntax_highlighter;
-	syntax_highlighter.instantiate(List<String>());
-
-	json_content = memnew(EditorJsonVisualizer);
-	json_content->load_theme(syntax_highlighter);
-	json_content->set_name(hdr_a_text);
-	json_content->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
-	json_content->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
-	json_box->add_child(json_content);
-
-	if (diff_data) {
-		VBoxContainer *diff_json_box = memnew(VBoxContainer);
-		diff_json_box->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
-		diff_json_box->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
-		box->add_child(diff_json_box);
-		String hrd_b_text = TTR("Snapshot B JSON");
-		SpanningHeader *hdr_b = memnew(SpanningHeader(hrd_b_text));
-		hdr_b->set_tooltip_text(TTR("Snapshot B:") + " " + diff_data->name);
-		diff_json_box->add_child(hdr_b);
-
-		diff_json_content = memnew(EditorJsonVisualizer);
-		diff_json_content->load_theme(syntax_highlighter);
-		diff_json_content->set_name(hrd_b_text);
-		diff_json_content->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
-		diff_json_content->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
-		diff_json_box->add_child(diff_json_content);
-	}
-
-	WorkerThreadPool::get_singleton()->add_native_task(&SnapshotJsonView::_serialization_worker, this);
-}
-
-String SnapshotJsonView::_snapshot_to_json(GameStateSnapshot *p_snapshot) {
-	if (p_snapshot == nullptr) {
-		return "";
-	}
-	Dictionary json_data;
-	json_data["name"] = p_snapshot->name;
-	Dictionary objects;
-	for (const KeyValue<ObjectID, SnapshotDataObject *> &obj : p_snapshot->objects) {
-		Dictionary obj_data;
-		obj_data["type_name"] = obj.value->type_name;
-
-		Array prop_list;
-		for (const PropertyInfo &prop : obj.value->prop_list) {
-			prop_list.push_back((Dictionary)prop);
-		}
-		objects["prop_list"] = prop_list;
-
-		Dictionary prop_values;
-		for (const KeyValue<StringName, Variant> &prop : obj.value->prop_values) {
-			// should only ever be one entry in this context
-			prop_values[prop.key] = prop.value;
-		}
-		obj_data["prop_values"] = prop_values;
-
-		objects[obj.key] = obj_data;
-	}
-	json_data["objects"] = objects;
-	return JSON::stringify(json_data, "    ", true, true);
-}
-
-void SnapshotJsonView::_serialization_worker(void *p_ud) {
-	// About 0.3s to serialize snapshots in a small game.
-	SnapshotJsonView *self = static_cast<SnapshotJsonView *>(p_ud);
-	GameStateSnapshot *snapshot_data = self->snapshot_data;
-	GameStateSnapshot *diff_data = self->diff_data;
-	// let the message queue figure out if self is still a valid object or if it's been destroyed.
-	MessageQueue::get_singleton()->push_call(self, "_update_text",
-			snapshot_data, diff_data,
-			_snapshot_to_json(snapshot_data),
-			_snapshot_to_json(diff_data));
-}
-
-void SnapshotJsonView::_update_text(GameStateSnapshot *p_data_ptr, GameStateSnapshot *p_diff_ptr, const String &p_data_str, const String &p_diff_data_str) {
-	if (p_data_ptr != snapshot_data || p_diff_ptr != diff_data) {
-		// If the GameStateSnapshots we generated strings for no longer match the snapshots we asked for,
-		// throw these results away. We'll get more from a different worker process.
-		return;
-	}
-
-	// About 5s to insert the string into the editor.
-	json_content->set_text(p_data_str);
-	if (diff_data) {
-		diff_json_content->set_text(p_diff_data_str);
-	}
-	loading_panel->queue_free();
-	// Loading json done, release the lock.
-}
-
-void SnapshotJsonView::_bind_methods() {
-	ClassDB::bind_method(D_METHOD("_update_text", "p_data_ptr", "p_diff_ptr", "p_data_str", "p_diff_data_str"), &SnapshotJsonView::_update_text);
-}

+ 0 - 58
modules/objectdb_profiler/editor/data_viewers/json_view.h

@@ -1,58 +0,0 @@
-/**************************************************************************/
-/*  json_view.h                                                           */
-/**************************************************************************/
-/*                         This file is part of:                          */
-/*                             GODOT ENGINE                               */
-/*                        https://godotengine.org                         */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
-/*                                                                        */
-/* Permission is hereby granted, free of charge, to any person obtaining  */
-/* a copy of this software and associated documentation files (the        */
-/* "Software"), to deal in the Software without restriction, including    */
-/* without limitation the rights to use, copy, modify, merge, publish,    */
-/* distribute, sublicense, and/or sell copies of the Software, and to     */
-/* permit persons to whom the Software is furnished to do so, subject to  */
-/* the following conditions:                                              */
-/*                                                                        */
-/* The above copyright notice and this permission notice shall be         */
-/* included in all copies or substantial portions of the Software.        */
-/*                                                                        */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
-/**************************************************************************/
-
-#pragma once
-
-#include "../snapshot_data.h"
-#include "snapshot_view.h"
-
-#include "editor/editor_json_visualizer.h"
-
-class SnapshotJsonView : public SnapshotView {
-	GDCLASS(SnapshotJsonView, SnapshotView);
-
-protected:
-	static void _serialization_worker(void *p_ud);
-	void _update_text(GameStateSnapshot *p_data_ptr, GameStateSnapshot *p_diff_ptr, const String &p_data_str, const String &p_diff_data_str);
-
-	static void _bind_methods();
-
-	EditorJsonVisualizer *json_content = nullptr;
-	EditorJsonVisualizer *diff_json_content = nullptr;
-
-	Control *loading_panel = nullptr;
-
-	void _load_theme_settings();
-	static String _snapshot_to_json(GameStateSnapshot *p_snapshot);
-
-public:
-	SnapshotJsonView();
-	virtual void show_snapshot(GameStateSnapshot *p_data, GameStateSnapshot *p_diff_data) override;
-};

+ 86 - 73
modules/objectdb_profiler/editor/data_viewers/node_view.cpp

@@ -33,10 +33,11 @@
 #include "editor/editor_node.h"
 #include "editor/editor_node.h"
 #include "editor/themes/editor_scale.h"
 #include "editor/themes/editor_scale.h"
 #include "scene/gui/check_button.h"
 #include "scene/gui/check_button.h"
+#include "scene/gui/popup_menu.h"
 #include "scene/gui/split_container.h"
 #include "scene/gui/split_container.h"
 
 
 SnapshotNodeView::SnapshotNodeView() {
 SnapshotNodeView::SnapshotNodeView() {
-	set_name("Nodes");
+	set_name(TTRC("Nodes"));
 }
 }
 
 
 void SnapshotNodeView::show_snapshot(GameStateSnapshot *p_data, GameStateSnapshot *p_diff_data) {
 void SnapshotNodeView::show_snapshot(GameStateSnapshot *p_data, GameStateSnapshot *p_diff_data) {
@@ -49,13 +50,12 @@ void SnapshotNodeView::show_snapshot(GameStateSnapshot *p_data, GameStateSnapsho
 	diff_sides->set_anchors_preset(LayoutPreset::PRESET_FULL_RECT);
 	diff_sides->set_anchors_preset(LayoutPreset::PRESET_FULL_RECT);
 	add_child(diff_sides);
 	add_child(diff_sides);
 
 
-	bool show_diff_label = diff_data && combined_diff_view;
-	main_tree = _make_node_tree(diff_data && !combined_diff_view ? TTR("A Nodes") : TTR("Nodes"), snapshot_data);
+	main_tree = _make_node_tree(diff_data && !combined_diff_view ? TTRC("A Nodes") : TTRC("Nodes"));
 	diff_sides->add_child(main_tree.root);
 	diff_sides->add_child(main_tree.root);
-	_add_snapshot_to_tree(main_tree.tree, snapshot_data, show_diff_label ? "-" : "");
+	_add_snapshot_to_tree(main_tree.tree, snapshot_data, diff_data && combined_diff_view ? DIFF_GROUP_REMOVED : DIFF_GROUP_NONE);
 
 
 	if (diff_data) {
 	if (diff_data) {
-		CheckButton *diff_mode_toggle = memnew(CheckButton(TTR("Combine Diff")));
+		CheckButton *diff_mode_toggle = memnew(CheckButton(TTRC("Combine Diff")));
 		diff_mode_toggle->set_pressed(combined_diff_view);
 		diff_mode_toggle->set_pressed(combined_diff_view);
 		diff_mode_toggle->connect(SceneStringName(toggled), callable_mp(this, &SnapshotNodeView::_toggle_diff_mode));
 		diff_mode_toggle->connect(SceneStringName(toggled), callable_mp(this, &SnapshotNodeView::_toggle_diff_mode));
 		main_tree.filter_bar->add_child(diff_mode_toggle);
 		main_tree.filter_bar->add_child(diff_mode_toggle);
@@ -63,12 +63,12 @@ void SnapshotNodeView::show_snapshot(GameStateSnapshot *p_data, GameStateSnapsho
 
 
 		if (combined_diff_view) {
 		if (combined_diff_view) {
 			// Merge the snapshots together and add a diff.
 			// Merge the snapshots together and add a diff.
-			_add_snapshot_to_tree(main_tree.tree, diff_data, "+");
+			_add_snapshot_to_tree(main_tree.tree, diff_data, DIFF_GROUP_ADDED);
 		} else {
 		} else {
 			// Add a second column with the diff snapshot.
 			// Add a second column with the diff snapshot.
-			diff_tree = _make_node_tree(TTR("B Nodes"), diff_data);
+			diff_tree = _make_node_tree(TTRC("B Nodes"));
 			diff_sides->add_child(diff_tree.root);
 			diff_sides->add_child(diff_tree.root);
-			_add_snapshot_to_tree(diff_tree.tree, diff_data, "");
+			_add_snapshot_to_tree(diff_tree.tree, diff_data, DIFF_GROUP_NONE);
 		}
 		}
 	}
 	}
 
 
@@ -84,12 +84,12 @@ void SnapshotNodeView::show_snapshot(GameStateSnapshot *p_data, GameStateSnapsho
 	choose_object_menu->connect(SceneStringName(id_pressed), callable_mp(this, &SnapshotNodeView::_choose_object_pressed).bind(false));
 	choose_object_menu->connect(SceneStringName(id_pressed), callable_mp(this, &SnapshotNodeView::_choose_object_pressed).bind(false));
 }
 }
 
 
-NodeTreeElements SnapshotNodeView::_make_node_tree(const String &p_tree_name, GameStateSnapshot *p_snapshot) {
+NodeTreeElements SnapshotNodeView::_make_node_tree(const String &p_tree_name) {
 	NodeTreeElements elements;
 	NodeTreeElements elements;
 	elements.root = memnew(VBoxContainer);
 	elements.root = memnew(VBoxContainer);
 	elements.root->set_anchors_preset(LayoutPreset::PRESET_FULL_RECT);
 	elements.root->set_anchors_preset(LayoutPreset::PRESET_FULL_RECT);
 	elements.tree = memnew(Tree);
 	elements.tree = memnew(Tree);
-	elements.filter_bar = memnew(TreeSortAndFilterBar(elements.tree, TTR("Filter Nodes")));
+	elements.filter_bar = memnew(TreeSortAndFilterBar(elements.tree, TTRC("Filter Nodes")));
 	elements.root->add_child(elements.filter_bar);
 	elements.root->add_child(elements.filter_bar);
 	elements.tree->set_select_mode(Tree::SelectMode::SELECT_ROW);
 	elements.tree->set_select_mode(Tree::SelectMode::SELECT_ROW);
 	elements.tree->set_custom_minimum_size(Size2(150, 0) * EDSCALE);
 	elements.tree->set_custom_minimum_size(Size2(150, 0) * EDSCALE);
@@ -125,14 +125,12 @@ void SnapshotNodeView::_node_selected(Tree *p_tree_selected_from) {
 		}
 		}
 	}
 	}
 
 
-	List<SnapshotDataObject *> &objects = tree_item_owners[p_tree_selected_from->get_selected()];
-	if (objects.is_empty()) {
+	const LocalVector<SnapshotDataObject *> &item_data = tree_item_data[p_tree_selected_from->get_selected()];
+	if (item_data.is_empty()) {
 		return;
 		return;
-	}
-	if (objects.size() == 1) {
-		EditorNode::get_singleton()->push_item((Object *)objects.get(0));
-	}
-	if (objects.size() == 2) {
+	} else if (item_data.size() == 1) {
+		EditorNode::get_singleton()->push_item(static_cast<Object *>(item_data[0]));
+	} else if (item_data.size() == 2) {
 		// This happens if we're in the combined diff view and the node exists in both trees
 		// This happens if we're in the combined diff view and the node exists in both trees
 		// The user has to specify which version of the node they want to see in the inspector.
 		// The user has to specify which version of the node they want to see in the inspector.
 		_show_choose_object_menu();
 		_show_choose_object_menu();
@@ -145,89 +143,105 @@ void SnapshotNodeView::_toggle_diff_mode(bool p_state) {
 }
 }
 
 
 void SnapshotNodeView::_notification(int p_what) {
 void SnapshotNodeView::_notification(int p_what) {
-	switch (p_what) {
-		case NOTIFICATION_ENTER_TREE:
-		case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
-		case NOTIFICATION_THEME_CHANGED:
-		case NOTIFICATION_TRANSLATION_CHANGED: {
-			_refresh_icons();
-		} break;
+	if (p_what == NOTIFICATION_THEME_CHANGED) {
+		_refresh_icons();
 	}
 	}
 }
 }
 
 
-void SnapshotNodeView::_add_snapshot_to_tree(Tree *p_tree, GameStateSnapshot *p_snapshot, const String &p_diff_group_name) {
+void SnapshotNodeView::_add_snapshot_to_tree(Tree *p_tree, GameStateSnapshot *p_snapshot, DiffGroup p_diff_group) {
+	SnapshotDataObject *scene_root = nullptr;
+	LocalVector<SnapshotDataObject *> orphan_nodes;
+
 	for (const KeyValue<ObjectID, SnapshotDataObject *> &kv : p_snapshot->objects) {
 	for (const KeyValue<ObjectID, SnapshotDataObject *> &kv : p_snapshot->objects) {
 		if (kv.value->is_node() && !kv.value->extra_debug_data.has("node_parent")) {
 		if (kv.value->is_node() && !kv.value->extra_debug_data.has("node_parent")) {
-			TreeItem *root_item = _add_child_named(p_tree, p_tree->get_root(), kv.value, p_diff_group_name);
-			_add_object_to_tree(root_item, kv.value, p_diff_group_name);
+			if (kv.value->extra_debug_data["node_is_scene_root"]) {
+				scene_root = kv.value;
+			} else {
+				orphan_nodes.push_back(kv.value);
+			}
+		}
+	}
+
+	if (scene_root != nullptr) {
+		TreeItem *root_item = _add_item_to_tree(p_tree, p_tree->get_root(), scene_root, p_diff_group);
+		_add_children_to_tree(root_item, scene_root, p_diff_group);
+	}
+
+	if (!orphan_nodes.is_empty()) {
+		TreeItem *orphans_item = _add_item_to_tree(p_tree, p_tree->get_root(), TTRC("Orphan Nodes"), p_diff_group);
+		for (SnapshotDataObject *orphan_node : orphan_nodes) {
+			TreeItem *orphan_item = _add_item_to_tree(p_tree, orphans_item, orphan_node, p_diff_group);
+			_add_children_to_tree(orphan_item, orphan_node, p_diff_group);
 		}
 		}
 	}
 	}
 }
 }
 
 
-void SnapshotNodeView::_add_object_to_tree(TreeItem *p_parent_item, SnapshotDataObject *p_data, const String &p_diff_group_name) {
-	for (const Variant &v : (Array)p_data->extra_debug_data["node_children"]) {
-		SnapshotDataObject *child_object = p_data->snapshot->objects[ObjectID((uint64_t)v)];
-		TreeItem *child_item = _add_child_named(p_parent_item->get_tree(), p_parent_item, child_object, p_diff_group_name);
-		_add_object_to_tree(child_item, child_object, p_diff_group_name);
+void SnapshotNodeView::_add_children_to_tree(TreeItem *p_parent_item, SnapshotDataObject *p_data, DiffGroup p_diff_group) {
+	for (const Variant &child_id : (Array)p_data->extra_debug_data["node_children"]) {
+		SnapshotDataObject *child_object = p_data->snapshot->objects[ObjectID((uint64_t)child_id)];
+		TreeItem *child_item = _add_item_to_tree(p_parent_item->get_tree(), p_parent_item, child_object, p_diff_group);
+		_add_children_to_tree(child_item, child_object, p_diff_group);
 	}
 	}
 }
 }
 
 
-TreeItem *SnapshotNodeView::_add_child_named(Tree *p_tree, TreeItem *p_item, SnapshotDataObject *p_item_owner, const String &p_diff_group_name) {
-	bool has_group = !p_diff_group_name.is_empty();
-	const String &item_name = p_item_owner->extra_debug_data["node_name"];
+TreeItem *SnapshotNodeView::_add_item_to_tree(Tree *p_tree, TreeItem *p_parent, const String &p_item_name, DiffGroup p_diff_group) {
 	// Find out if this node already exists.
 	// Find out if this node already exists.
-	TreeItem *child_item = nullptr;
-	if (has_group) {
-		for (int idx = 0; idx < p_item->get_child_count(); idx++) {
-			TreeItem *child = p_item->get_child(idx);
-			if (child->get_text(0) == item_name) {
-				child_item = child;
+	TreeItem *item = nullptr;
+	if (p_diff_group != DIFF_GROUP_NONE) {
+		for (int idx = 0; idx < p_parent->get_child_count(); idx++) {
+			TreeItem *child = p_parent->get_child(idx);
+			if (child->get_text(0) == p_item_name) {
+				item = child;
 				break;
 				break;
 			}
 			}
 		}
 		}
 	}
 	}
 
 
-	if (child_item) {
+	if (item) {
 		// If it exists, clear the background color because we now know it exists in both trees.
 		// If it exists, clear the background color because we now know it exists in both trees.
-		child_item->clear_custom_bg_color(0);
+		item->clear_custom_bg_color(0);
 	} else {
 	} else {
-		// Add the new node and set it's background color to green or red depending on which snapshot it's a part of.
-		if (p_item_owner->extra_debug_data["node_is_scene_root"]) {
-			child_item = p_tree->get_root() ? p_tree->get_root() : p_tree->create_item();
-		} else {
-			child_item = p_tree->create_item(p_item);
-		}
-		if (has_group) {
-			if (p_diff_group_name == "+") {
-				child_item->set_custom_bg_color(0, Color(0, 1, 0, 0.1));
-			}
-			if (p_diff_group_name == "-") {
-				child_item->set_custom_bg_color(0, Color(1, 0, 0, 0.1));
-			}
+		// Add the new node and set its background color to green or red depending on which snapshot it's a part of.
+		item = p_tree->create_item(p_parent);
+
+		if (p_diff_group == DIFF_GROUP_ADDED) {
+			item->set_custom_bg_color(0, Color(0, 1, 0, 0.1));
+		} else if (p_diff_group == DIFF_GROUP_REMOVED) {
+			item->set_custom_bg_color(0, Color(1, 0, 0, 0.1));
 		}
 		}
 	}
 	}
 
 
-	child_item->set_text(0, item_name);
-	_add_tree_item_owner(child_item, p_item_owner);
-	return child_item;
+	item->set_text(0, p_item_name);
+	item->set_auto_translate_mode(0, AUTO_TRANSLATE_MODE_DISABLED);
+
+	return item;
 }
 }
 
 
-// Each node in the tree may be part of one or two snapshots. This tracks that relationship
-// so we can display the correct data in the inspector if a node is clicked.
-void SnapshotNodeView::_add_tree_item_owner(TreeItem *p_item, SnapshotDataObject *p_owner) {
-	if (!tree_item_owners.has(p_item)) {
-		tree_item_owners.insert(p_item, List<SnapshotDataObject *>());
-	}
-	tree_item_owners[p_item].push_back(p_owner);
+TreeItem *SnapshotNodeView::_add_item_to_tree(Tree *p_tree, TreeItem *p_parent, SnapshotDataObject *p_data, DiffGroup p_diff_group) {
+	String node_name = p_data->extra_debug_data["node_name"];
+	TreeItem *child_item = _add_item_to_tree(p_tree, p_parent, node_name, p_diff_group);
+	tree_item_data[child_item].push_back(p_data);
+	return child_item;
 }
 }
 
 
 void SnapshotNodeView::_refresh_icons() {
 void SnapshotNodeView::_refresh_icons() {
 	for (TreeItem *item : _get_children_recursive(main_tree.tree)) {
 	for (TreeItem *item : _get_children_recursive(main_tree.tree)) {
-		item->set_icon(0, EditorNode::get_singleton()->get_class_icon(tree_item_owners[item].get(0)->type_name, ""));
+		HashMap<TreeItem *, LocalVector<SnapshotDataObject *>>::Iterator E = tree_item_data.find(item);
+		if (E && !E->value.is_empty()) {
+			item->set_icon(0, EditorNode::get_singleton()->get_class_icon(E->value[0]->type_name));
+		} else {
+			item->set_icon(0, EditorNode::get_singleton()->get_class_icon("MissingNode"));
+		}
 	}
 	}
+
 	if (diff_tree.tree) {
 	if (diff_tree.tree) {
 		for (TreeItem *item : _get_children_recursive(diff_tree.tree)) {
 		for (TreeItem *item : _get_children_recursive(diff_tree.tree)) {
-			item->set_icon(0, EditorNode::get_singleton()->get_class_icon(tree_item_owners[item].get(0)->type_name, ""));
+			HashMap<TreeItem *, LocalVector<SnapshotDataObject *>>::Iterator E = tree_item_data.find(item);
+			if (E && !E->value.is_empty()) {
+				item->set_icon(0, EditorNode::get_singleton()->get_class_icon(E->value[0]->type_name));
+			} else {
+				item->set_icon(0, EditorNode::get_singleton()->get_class_icon("MissingNode"));
+			}
 		}
 		}
 	}
 	}
 }
 }
@@ -235,7 +249,7 @@ void SnapshotNodeView::_refresh_icons() {
 void SnapshotNodeView::clear_snapshot() {
 void SnapshotNodeView::clear_snapshot() {
 	SnapshotView::clear_snapshot();
 	SnapshotView::clear_snapshot();
 
 
-	tree_item_owners.clear();
+	tree_item_data.clear();
 	main_tree.tree = nullptr;
 	main_tree.tree = nullptr;
 	main_tree.filter_bar = nullptr;
 	main_tree.filter_bar = nullptr;
 	main_tree.root = nullptr;
 	main_tree.root = nullptr;
@@ -246,16 +260,15 @@ void SnapshotNodeView::clear_snapshot() {
 }
 }
 
 
 void SnapshotNodeView::_choose_object_pressed(int p_object_idx, bool p_confirm_override) {
 void SnapshotNodeView::_choose_object_pressed(int p_object_idx, bool p_confirm_override) {
-	List<SnapshotDataObject *> &objects = tree_item_owners[active_tree->get_selected()];
-	EditorNode::get_singleton()->push_item((Object *)objects.get(p_object_idx));
+	EditorNode::get_singleton()->push_item(static_cast<Object *>(tree_item_data[active_tree->get_selected()][p_object_idx]));
 }
 }
 
 
 void SnapshotNodeView::_show_choose_object_menu() {
 void SnapshotNodeView::_show_choose_object_menu() {
 	remove_child(choose_object_menu);
 	remove_child(choose_object_menu);
 	add_child(choose_object_menu);
 	add_child(choose_object_menu);
 	choose_object_menu->clear(false);
 	choose_object_menu->clear(false);
-	choose_object_menu->add_item(TTR("Snapshot A"), 0);
-	choose_object_menu->add_item(TTR("Snapshot B"), 1);
+	choose_object_menu->add_item(TTRC("Snapshot A"), 0);
+	choose_object_menu->add_item(TTRC("Snapshot B"), 1);
 	choose_object_menu->reset_size();
 	choose_object_menu->reset_size();
 	choose_object_menu->set_position(get_screen_position() + get_local_mouse_position());
 	choose_object_menu->set_position(get_screen_position() + get_local_mouse_position());
 	choose_object_menu->popup();
 	choose_object_menu->popup();

+ 12 - 11
modules/objectdb_profiler/editor/data_viewers/node_view.h

@@ -52,31 +52,32 @@ struct NodeTreeElements {
 class SnapshotNodeView : public SnapshotView {
 class SnapshotNodeView : public SnapshotView {
 	GDCLASS(SnapshotNodeView, SnapshotView);
 	GDCLASS(SnapshotNodeView, SnapshotView);
 
 
-protected:
+	enum DiffGroup {
+		DIFF_GROUP_NONE,
+		DIFF_GROUP_ADDED,
+		DIFF_GROUP_REMOVED
+	};
+
 	NodeTreeElements main_tree;
 	NodeTreeElements main_tree;
 	NodeTreeElements diff_tree;
 	NodeTreeElements diff_tree;
 	Tree *active_tree = nullptr;
 	Tree *active_tree = nullptr;
 	PopupMenu *choose_object_menu = nullptr;
 	PopupMenu *choose_object_menu = nullptr;
 	bool combined_diff_view = true;
 	bool combined_diff_view = true;
-	HashMap<TreeItem *, List<SnapshotDataObject *>> tree_item_owners;
+	HashMap<TreeItem *, LocalVector<SnapshotDataObject *>> tree_item_data;
 
 
 	void _node_selected(Tree *p_tree_selected_from);
 	void _node_selected(Tree *p_tree_selected_from);
 	void _notification(int p_what);
 	void _notification(int p_what);
-	NodeTreeElements _make_node_tree(const String &p_tree_name, GameStateSnapshot *p_snapshot);
+	NodeTreeElements _make_node_tree(const String &p_tree_name);
 	void _apply_filters();
 	void _apply_filters();
 	void _refresh_icons();
 	void _refresh_icons();
 	void _toggle_diff_mode(bool p_state);
 	void _toggle_diff_mode(bool p_state);
 	void _choose_object_pressed(int p_object_idx, bool p_confirm_override);
 	void _choose_object_pressed(int p_object_idx, bool p_confirm_override);
 	void _show_choose_object_menu();
 	void _show_choose_object_menu();
 
 
-	// `_add_snapshot_to_tree`, `_add_object_to_tree`, and `_add_child_named` work together to add items to the node tree.
-	// They support adding two snapshots to the same tree, and will highlight rows to show additions and removals.
-	// `_add_snapshot_to_tree` walks the root items in the tree and adds them first, then `_add_object_to_tree` recursively
-	// adds all the child items. `_add_child_named` is used by both to add each individual items.
-	void _add_snapshot_to_tree(Tree *p_tree, GameStateSnapshot *p_snapshot, const String &p_diff_group_name = "");
-	void _add_object_to_tree(TreeItem *p_parent_item, SnapshotDataObject *p_data, const String &p_diff_group_name = "");
-	TreeItem *_add_child_named(Tree *p_tree, TreeItem *p_item, SnapshotDataObject *p_item_owner, const String &p_diff_group_name = "");
-	void _add_tree_item_owner(TreeItem *p_item, SnapshotDataObject *p_owner);
+	void _add_snapshot_to_tree(Tree *p_tree, GameStateSnapshot *p_snapshot, DiffGroup p_diff_group = DIFF_GROUP_NONE);
+	void _add_children_to_tree(TreeItem *p_parent_item, SnapshotDataObject *p_data, DiffGroup p_diff_group = DIFF_GROUP_NONE);
+	TreeItem *_add_item_to_tree(Tree *p_tree, TreeItem *p_parent, const String &p_item_name, DiffGroup p_diff_group = DIFF_GROUP_NONE);
+	TreeItem *_add_item_to_tree(Tree *p_tree, TreeItem *p_parent, SnapshotDataObject *p_data, DiffGroup p_diff_group = DIFF_GROUP_NONE);
 
 
 public:
 public:
 	SnapshotNodeView();
 	SnapshotNodeView();

+ 30 - 21
modules/objectdb_profiler/editor/data_viewers/object_view.cpp

@@ -36,7 +36,7 @@
 #include "scene/gui/split_container.h"
 #include "scene/gui/split_container.h"
 
 
 SnapshotObjectView::SnapshotObjectView() {
 SnapshotObjectView::SnapshotObjectView() {
-	set_name(TTR("Objects"));
+	set_name(TTRC("Objects"));
 }
 }
 
 
 void SnapshotObjectView::show_snapshot(GameStateSnapshot *p_data, GameStateSnapshot *p_diff_data) {
 void SnapshotObjectView::show_snapshot(GameStateSnapshot *p_data, GameStateSnapshot *p_diff_data) {
@@ -60,17 +60,17 @@ void SnapshotObjectView::show_snapshot(GameStateSnapshot *p_data, GameStateSnaps
 
 
 	object_list = memnew(Tree);
 	object_list = memnew(Tree);
 
 
-	filter_bar = memnew(TreeSortAndFilterBar(object_list, TTR("Filter Objects")));
+	filter_bar = memnew(TreeSortAndFilterBar(object_list, TTRC("Filter Objects")));
 	object_column->add_child(filter_bar);
 	object_column->add_child(filter_bar);
 	int sort_idx = 0;
 	int sort_idx = 0;
 	if (diff_data) {
 	if (diff_data) {
-		filter_bar->add_sort_option(TTR("Snapshot"), TreeSortAndFilterBar::SortType::ALPHA_SORT, sort_idx++);
+		filter_bar->add_sort_option(TTRC("Snapshot"), TreeSortAndFilterBar::SortType::ALPHA_SORT, sort_idx++);
 	}
 	}
-	filter_bar->add_sort_option(TTR("Class"), TreeSortAndFilterBar::SortType::ALPHA_SORT, sort_idx++);
-	filter_bar->add_sort_option(TTR("Name"), TreeSortAndFilterBar::SortType::ALPHA_SORT, sort_idx++);
-	filter_bar->add_sort_option(TTR("Inbound References"), TreeSortAndFilterBar::SortType::NUMERIC_SORT, sort_idx++);
+	filter_bar->add_sort_option(TTRC("Class"), TreeSortAndFilterBar::SortType::ALPHA_SORT, sort_idx++);
+	filter_bar->add_sort_option(TTRC("Name"), TreeSortAndFilterBar::SortType::ALPHA_SORT, sort_idx++);
+	filter_bar->add_sort_option(TTRC("Inbound References"), TreeSortAndFilterBar::SortType::NUMERIC_SORT, sort_idx++);
 	TreeSortAndFilterBar::SortOptionIndexes default_sort = filter_bar->add_sort_option(
 	TreeSortAndFilterBar::SortOptionIndexes default_sort = filter_bar->add_sort_option(
-			TTR("Outbound References"), TreeSortAndFilterBar::SortType::NUMERIC_SORT, sort_idx++);
+			TTRC("Outbound References"), TreeSortAndFilterBar::SortType::NUMERIC_SORT, sort_idx++);
 
 
 	// Tree of objects.
 	// Tree of objects.
 	object_list->set_select_mode(Tree::SelectMode::SELECT_ROW);
 	object_list->set_select_mode(Tree::SelectMode::SELECT_ROW);
@@ -82,27 +82,27 @@ void SnapshotObjectView::show_snapshot(GameStateSnapshot *p_data, GameStateSnaps
 	object_list->set_column_titles_visible(true);
 	object_list->set_column_titles_visible(true);
 	int offset = 0;
 	int offset = 0;
 	if (diff_data) {
 	if (diff_data) {
-		object_list->set_column_title(0, TTR("Snapshot"));
+		object_list->set_column_title(0, TTRC("Snapshot"));
 		object_list->set_column_expand(0, false);
 		object_list->set_column_expand(0, false);
 		object_list->set_column_title_tooltip_text(0, "A: " + snapshot_data->name + ", B: " + diff_data->name);
 		object_list->set_column_title_tooltip_text(0, "A: " + snapshot_data->name + ", B: " + diff_data->name);
 		offset++;
 		offset++;
 	}
 	}
-	object_list->set_column_title(offset + 0, TTR("Class"));
+	object_list->set_column_title(offset + 0, TTRC("Class"));
 	object_list->set_column_expand(offset + 0, true);
 	object_list->set_column_expand(offset + 0, true);
-	object_list->set_column_title_tooltip_text(offset + 0, TTR("Object's class"));
-	object_list->set_column_title(offset + 1, TTR("Object"));
+	object_list->set_column_title_tooltip_text(offset + 0, TTRC("Object's class"));
+	object_list->set_column_title(offset + 1, TTRC("Object"));
 	object_list->set_column_expand(offset + 1, true);
 	object_list->set_column_expand(offset + 1, true);
 	object_list->set_column_expand_ratio(offset + 1, 2);
 	object_list->set_column_expand_ratio(offset + 1, 2);
-	object_list->set_column_title_tooltip_text(offset + 1, TTR("Object's name"));
-	object_list->set_column_title(offset + 2, TTR("In"));
+	object_list->set_column_title_tooltip_text(offset + 1, TTRC("Object's name"));
+	object_list->set_column_title(offset + 2, TTRC("In"));
 	object_list->set_column_expand(offset + 2, false);
 	object_list->set_column_expand(offset + 2, false);
 	object_list->set_column_clip_content(offset + 2, false);
 	object_list->set_column_clip_content(offset + 2, false);
-	object_list->set_column_title_tooltip_text(offset + 2, TTR("Number of inbound references"));
+	object_list->set_column_title_tooltip_text(offset + 2, TTRC("Number of inbound references"));
 	object_list->set_column_custom_minimum_width(offset + 2, 30 * EDSCALE);
 	object_list->set_column_custom_minimum_width(offset + 2, 30 * EDSCALE);
-	object_list->set_column_title(offset + 3, TTR("Out"));
+	object_list->set_column_title(offset + 3, TTRC("Out"));
 	object_list->set_column_expand(offset + 3, false);
 	object_list->set_column_expand(offset + 3, false);
 	object_list->set_column_clip_content(offset + 3, false);
 	object_list->set_column_clip_content(offset + 3, false);
-	object_list->set_column_title_tooltip_text(offset + 3, TTR("Number of outbound references"));
+	object_list->set_column_title_tooltip_text(offset + 3, TTRC("Number of outbound references"));
 	object_list->set_column_custom_minimum_width(offset + 2, 30 * EDSCALE);
 	object_list->set_column_custom_minimum_width(offset + 2, 30 * EDSCALE);
 	object_list->connect(SceneStringName(item_selected), callable_mp(this, &SnapshotObjectView::_object_selected));
 	object_list->connect(SceneStringName(item_selected), callable_mp(this, &SnapshotObjectView::_object_selected));
 	object_list->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 	object_list->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
@@ -115,9 +115,9 @@ void SnapshotObjectView::show_snapshot(GameStateSnapshot *p_data, GameStateSnaps
 	object_details->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 	object_details->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 
 
 	object_list->create_item();
 	object_list->create_item();
-	_insert_data(snapshot_data, TTR("A"));
+	_insert_data(snapshot_data, TTRC("A"));
 	if (diff_data) {
 	if (diff_data) {
-		_insert_data(diff_data, TTR("B"));
+		_insert_data(diff_data, TTRC("B"));
 	}
 	}
 
 
 	filter_bar->select_sort(default_sort.descending);
 	filter_bar->select_sort(default_sort.descending);
@@ -136,8 +136,11 @@ void SnapshotObjectView::_insert_data(GameStateSnapshot *p_snapshot, const Strin
 		if (diff_data) {
 		if (diff_data) {
 			item->set_text(0, p_name);
 			item->set_text(0, p_name);
 			item->set_tooltip_text(0, p_snapshot->name);
 			item->set_tooltip_text(0, p_snapshot->name);
+			item->set_auto_translate_mode(0, AUTO_TRANSLATE_MODE_DISABLED);
 			offset = 1;
 			offset = 1;
 		}
 		}
+		item->set_auto_translate_mode(offset + 0, AUTO_TRANSLATE_MODE_DISABLED);
+		item->set_auto_translate_mode(offset + 1, AUTO_TRANSLATE_MODE_DISABLED);
 		item->set_text(offset + 0, pair.value->type_name);
 		item->set_text(offset + 0, pair.value->type_name);
 		item->set_text(offset + 1, pair.value->get_name());
 		item->set_text(offset + 1, pair.value->get_name());
 		item->set_text(offset + 2, String::num_uint64(pair.value->inbound_references.size()));
 		item->set_text(offset + 2, String::num_uint64(pair.value->inbound_references.size()));
@@ -155,7 +158,7 @@ void SnapshotObjectView::_object_selected() {
 	}
 	}
 
 
 	SnapshotDataObject *d = item_data_map[object_list->get_selected()];
 	SnapshotDataObject *d = item_data_map[object_list->get_selected()];
-	EditorNode::get_singleton()->push_item((Object *)d);
+	EditorNode::get_singleton()->push_item(static_cast<Object *>(d));
 
 
 	DarkPanelContainer *object_panel = memnew(DarkPanelContainer);
 	DarkPanelContainer *object_panel = memnew(DarkPanelContainer);
 	VBoxContainer *object_panel_content = memnew(VBoxContainer);
 	VBoxContainer *object_panel_content = memnew(VBoxContainer);
@@ -177,22 +180,28 @@ void SnapshotObjectView::_object_selected() {
 	properties_scroll->add_child(properties_container);
 	properties_scroll->add_child(properties_container);
 	properties_container->add_theme_constant_override("separation", 8);
 	properties_container->add_theme_constant_override("separation", 8);
 
 
-	inbound_tree = _make_references_list(properties_container, TTR("Inbound References"), TTR("Source"), TTR("Other object referencing this object"), TTR("Property"), TTR("Property of other object referencing this object"));
+	inbound_tree = _make_references_list(properties_container, TTRC("Inbound References"), TTRC("Source"), TTRC("Other object referencing this object"), TTRC("Property"), TTRC("Property of other object referencing this object"));
 	inbound_tree->connect(SceneStringName(item_selected), callable_mp(this, &SnapshotObjectView::_reference_selected).bind(inbound_tree));
 	inbound_tree->connect(SceneStringName(item_selected), callable_mp(this, &SnapshotObjectView::_reference_selected).bind(inbound_tree));
 	TreeItem *ib_root = inbound_tree->create_item();
 	TreeItem *ib_root = inbound_tree->create_item();
 	for (const KeyValue<String, ObjectID> &ob : d->inbound_references) {
 	for (const KeyValue<String, ObjectID> &ob : d->inbound_references) {
 		TreeItem *i = inbound_tree->create_item(ib_root);
 		TreeItem *i = inbound_tree->create_item(ib_root);
+		i->set_auto_translate_mode(0, AUTO_TRANSLATE_MODE_DISABLED);
+		i->set_auto_translate_mode(1, AUTO_TRANSLATE_MODE_DISABLED);
+
 		SnapshotDataObject *target = d->snapshot->objects[ob.value];
 		SnapshotDataObject *target = d->snapshot->objects[ob.value];
 		i->set_text(0, target->get_name());
 		i->set_text(0, target->get_name());
 		i->set_text(1, ob.key);
 		i->set_text(1, ob.key);
 		reference_item_map[i] = data_item_map[target];
 		reference_item_map[i] = data_item_map[target];
 	}
 	}
 
 
-	outbound_tree = _make_references_list(properties_container, TTR("Outbound References"), TTR("Property"), TTR("Property of this object referencing other object"), TTR("Target"), TTR("Other object being referenced"));
+	outbound_tree = _make_references_list(properties_container, TTRC("Outbound References"), TTRC("Property"), TTRC("Property of this object referencing other object"), TTRC("Target"), TTRC("Other object being referenced"));
 	outbound_tree->connect(SceneStringName(item_selected), callable_mp(this, &SnapshotObjectView::_reference_selected).bind(outbound_tree));
 	outbound_tree->connect(SceneStringName(item_selected), callable_mp(this, &SnapshotObjectView::_reference_selected).bind(outbound_tree));
 	TreeItem *ob_root = outbound_tree->create_item();
 	TreeItem *ob_root = outbound_tree->create_item();
 	for (const KeyValue<String, ObjectID> &ob : d->outbound_references) {
 	for (const KeyValue<String, ObjectID> &ob : d->outbound_references) {
 		TreeItem *i = outbound_tree->create_item(ob_root);
 		TreeItem *i = outbound_tree->create_item(ob_root);
+		i->set_auto_translate_mode(0, AUTO_TRANSLATE_MODE_DISABLED);
+		i->set_auto_translate_mode(1, AUTO_TRANSLATE_MODE_DISABLED);
+
 		SnapshotDataObject *target = d->snapshot->objects[ob.value];
 		SnapshotDataObject *target = d->snapshot->objects[ob.value];
 		i->set_text(0, ob.key);
 		i->set_text(0, ob.key);
 		i->set_text(1, target->get_name());
 		i->set_text(1, target->get_name());

+ 51 - 38
modules/objectdb_profiler/editor/data_viewers/refcounted_view.cpp

@@ -36,7 +36,7 @@
 #include "scene/gui/split_container.h"
 #include "scene/gui/split_container.h"
 
 
 SnapshotRefCountedView::SnapshotRefCountedView() {
 SnapshotRefCountedView::SnapshotRefCountedView() {
-	set_name(TTR("RefCounted"));
+	set_name(TTRC("RefCounted"));
 }
 }
 
 
 void SnapshotRefCountedView::show_snapshot(GameStateSnapshot *p_data, GameStateSnapshot *p_diff_data) {
 void SnapshotRefCountedView::show_snapshot(GameStateSnapshot *p_data, GameStateSnapshot *p_diff_data) {
@@ -59,21 +59,21 @@ void SnapshotRefCountedView::show_snapshot(GameStateSnapshot *p_data, GameStateS
 	// Tree of Refs.
 	// Tree of Refs.
 	refs_list = memnew(Tree);
 	refs_list = memnew(Tree);
 
 
-	filter_bar = memnew(TreeSortAndFilterBar(refs_list, TTR("Filter RefCounteds")));
+	filter_bar = memnew(TreeSortAndFilterBar(refs_list, TTRC("Filter RefCounteds")));
 	refs_column->add_child(filter_bar);
 	refs_column->add_child(filter_bar);
 	int offset = diff_data ? 1 : 0;
 	int offset = diff_data ? 1 : 0;
 	if (diff_data) {
 	if (diff_data) {
-		filter_bar->add_sort_option(TTR("Snapshot"), TreeSortAndFilterBar::SortType::ALPHA_SORT, 0);
+		filter_bar->add_sort_option(TTRC("Snapshot"), TreeSortAndFilterBar::SortType::ALPHA_SORT, 0);
 	}
 	}
-	filter_bar->add_sort_option(TTR("Class"), TreeSortAndFilterBar::SortType::ALPHA_SORT, offset + 0);
-	filter_bar->add_sort_option(TTR("Name"), TreeSortAndFilterBar::SortType::ALPHA_SORT, offset + 1);
+	filter_bar->add_sort_option(TTRC("Class"), TreeSortAndFilterBar::SortType::ALPHA_SORT, offset + 0);
+	filter_bar->add_sort_option(TTRC("Name"), TreeSortAndFilterBar::SortType::ALPHA_SORT, offset + 1);
 	TreeSortAndFilterBar::SortOptionIndexes default_sort = filter_bar->add_sort_option(
 	TreeSortAndFilterBar::SortOptionIndexes default_sort = filter_bar->add_sort_option(
-			TTR("Native Refs"),
+			TTRC("Native Refs"),
 			TreeSortAndFilterBar::SortType::NUMERIC_SORT,
 			TreeSortAndFilterBar::SortType::NUMERIC_SORT,
 			offset + 2);
 			offset + 2);
-	filter_bar->add_sort_option(TTR("ObjectDB Refs"), TreeSortAndFilterBar::SortType::NUMERIC_SORT, offset + 3);
-	filter_bar->add_sort_option(TTR("Total Refs"), TreeSortAndFilterBar::SortType::NUMERIC_SORT, offset + 4);
-	filter_bar->add_sort_option(TTR("ObjectDB Cycles"), TreeSortAndFilterBar::SortType::NUMERIC_SORT, offset + 5);
+	filter_bar->add_sort_option(TTRC("ObjectDB Refs"), TreeSortAndFilterBar::SortType::NUMERIC_SORT, offset + 3);
+	filter_bar->add_sort_option(TTRC("Total Refs"), TreeSortAndFilterBar::SortType::NUMERIC_SORT, offset + 4);
+	filter_bar->add_sort_option(TTRC("ObjectDB Cycles"), TreeSortAndFilterBar::SortType::NUMERIC_SORT, offset + 5);
 
 
 	refs_list->set_select_mode(Tree::SelectMode::SELECT_ROW);
 	refs_list->set_select_mode(Tree::SelectMode::SELECT_ROW);
 	refs_list->set_custom_minimum_size(Size2(200, 0) * EDSCALE);
 	refs_list->set_custom_minimum_size(Size2(200, 0) * EDSCALE);
@@ -82,30 +82,38 @@ void SnapshotRefCountedView::show_snapshot(GameStateSnapshot *p_data, GameStateS
 	refs_list->set_hide_root(true);
 	refs_list->set_hide_root(true);
 	refs_list->set_columns(diff_data ? 7 : 6);
 	refs_list->set_columns(diff_data ? 7 : 6);
 	refs_list->set_column_titles_visible(true);
 	refs_list->set_column_titles_visible(true);
+
 	if (diff_data) {
 	if (diff_data) {
-		refs_list->set_column_title(0, TTR("Snapshot"));
+		refs_list->set_column_title(0, TTRC("Snapshot"));
 		refs_list->set_column_expand(0, false);
 		refs_list->set_column_expand(0, false);
 		refs_list->set_column_title_tooltip_text(0, "A: " + snapshot_data->name + ", B: " + diff_data->name);
 		refs_list->set_column_title_tooltip_text(0, "A: " + snapshot_data->name + ", B: " + diff_data->name);
 	}
 	}
-	refs_list->set_column_title(offset + 0, TTR("Class"));
+
+	refs_list->set_column_title(offset + 0, TTRC("Class"));
 	refs_list->set_column_expand(offset + 0, true);
 	refs_list->set_column_expand(offset + 0, true);
-	refs_list->set_column_title_tooltip_text(offset + 0, TTR("Object's class"));
-	refs_list->set_column_title(offset + 1, TTR("Name"));
+	refs_list->set_column_title_tooltip_text(offset + 0, TTRC("Object's class"));
+
+	refs_list->set_column_title(offset + 1, TTRC("Name"));
 	refs_list->set_column_expand(offset + 1, true);
 	refs_list->set_column_expand(offset + 1, true);
 	refs_list->set_column_expand_ratio(offset + 1, 2);
 	refs_list->set_column_expand_ratio(offset + 1, 2);
-	refs_list->set_column_title_tooltip_text(offset + 1, TTR("Object's name"));
-	refs_list->set_column_title(offset + 2, TTR("Native Refs"));
+	refs_list->set_column_title_tooltip_text(offset + 1, TTRC("Object's name"));
+
+	refs_list->set_column_title(offset + 2, TTRC("Native Refs"));
 	refs_list->set_column_expand(offset + 2, false);
 	refs_list->set_column_expand(offset + 2, false);
-	refs_list->set_column_title_tooltip_text(offset + 2, TTR("References not owned by the ObjectDB"));
-	refs_list->set_column_title(offset + 3, TTR("ObjectDB Refs"));
+	refs_list->set_column_title_tooltip_text(offset + 2, TTRC("References not owned by the ObjectDB"));
+
+	refs_list->set_column_title(offset + 3, TTRC("ObjectDB Refs"));
 	refs_list->set_column_expand(offset + 3, false);
 	refs_list->set_column_expand(offset + 3, false);
-	refs_list->set_column_title_tooltip_text(offset + 3, TTR("References owned by the ObjectDB"));
-	refs_list->set_column_title(offset + 4, TTR("Total Refs"));
+	refs_list->set_column_title_tooltip_text(offset + 3, TTRC("References owned by the ObjectDB"));
+
+	refs_list->set_column_title(offset + 4, TTRC("Total Refs"));
 	refs_list->set_column_expand(offset + 4, false);
 	refs_list->set_column_expand(offset + 4, false);
-	refs_list->set_column_title_tooltip_text(offset + 4, TTR("ObjectDB References + Native References"));
-	refs_list->set_column_title(offset + 5, TTR("ObjectDB Cycles"));
+	refs_list->set_column_title_tooltip_text(offset + 4, TTRC("ObjectDB References + Native References"));
+
+	refs_list->set_column_title(offset + 5, TTRC("ObjectDB Cycles"));
 	refs_list->set_column_expand(offset + 5, false);
 	refs_list->set_column_expand(offset + 5, false);
-	refs_list->set_column_title_tooltip_text(offset + 5, TTR("Cycles detected in the ObjectDB"));
+	refs_list->set_column_title_tooltip_text(offset + 5, TTRC("Cycles detected in the ObjectDB"));
+
 	refs_list->connect(SceneStringName(item_selected), callable_mp(this, &SnapshotRefCountedView::_refcounted_selected));
 	refs_list->connect(SceneStringName(item_selected), callable_mp(this, &SnapshotRefCountedView::_refcounted_selected));
 	refs_list->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 	refs_list->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 	refs_list->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 	refs_list->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
@@ -118,9 +126,9 @@ void SnapshotRefCountedView::show_snapshot(GameStateSnapshot *p_data, GameStateS
 	ref_details->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 	ref_details->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 
 
 	refs_list->create_item();
 	refs_list->create_item();
-	_insert_data(snapshot_data, TTR("A"));
+	_insert_data(snapshot_data, TTRC("A"));
 	if (diff_data) {
 	if (diff_data) {
-		_insert_data(diff_data, TTR("B"));
+		_insert_data(diff_data, TTRC("B"));
 	}
 	}
 
 
 	// Push the split as far right as possible.
 	// Push the split as far right as possible.
@@ -154,11 +162,14 @@ void SnapshotRefCountedView::_insert_data(GameStateSnapshot *p_snapshot, const S
 		if (diff_data) {
 		if (diff_data) {
 			item->set_text(0, p_name);
 			item->set_text(0, p_name);
 			item->set_tooltip_text(0, p_snapshot->name);
 			item->set_tooltip_text(0, p_snapshot->name);
+			item->set_auto_translate_mode(0, AUTO_TRANSLATE_MODE_DISABLED);
 			offset = 1;
 			offset = 1;
 		}
 		}
 
 
 		item->set_text(offset + 0, pair.value->type_name);
 		item->set_text(offset + 0, pair.value->type_name);
+		item->set_auto_translate_mode(offset + 0, AUTO_TRANSLATE_MODE_DISABLED);
 		item->set_text(offset + 1, pair.value->get_name());
 		item->set_text(offset + 1, pair.value->get_name());
+		item->set_auto_translate_mode(offset + 1, AUTO_TRANSLATE_MODE_DISABLED);
 		item->set_text(offset + 2, String::num_uint64(native_refs));
 		item->set_text(offset + 2, String::num_uint64(native_refs));
 		item->set_text(offset + 3, String::num_uint64(objectdb_refs));
 		item->set_text(offset + 3, String::num_uint64(objectdb_refs));
 		item->set_text(offset + 4, String::num_uint64(total_refs));
 		item->set_text(offset + 4, String::num_uint64(total_refs));
@@ -179,7 +190,7 @@ void SnapshotRefCountedView::_refcounted_selected() {
 	}
 	}
 
 
 	SnapshotDataObject *d = item_data_map[refs_list->get_selected()];
 	SnapshotDataObject *d = item_data_map[refs_list->get_selected()];
-	EditorNode::get_singleton()->push_item((Object *)d);
+	EditorNode::get_singleton()->push_item(static_cast<Object *>(d));
 
 
 	DarkPanelContainer *refcounted_panel = memnew(DarkPanelContainer);
 	DarkPanelContainer *refcounted_panel = memnew(DarkPanelContainer);
 	VBoxContainer *refcounted_panel_content = memnew(VBoxContainer);
 	VBoxContainer *refcounted_panel_content = memnew(VBoxContainer);
@@ -211,10 +222,10 @@ void SnapshotRefCountedView::_refcounted_selected() {
 	Array ref_cycles = (Array)d->extra_debug_data["ref_cycles"];
 	Array ref_cycles = (Array)d->extra_debug_data["ref_cycles"];
 
 
 	String count_str = "[ul]\n";
 	String count_str = "[ul]\n";
-	count_str += TTR(" Native References: ") + String::num_uint64(native_refs) + "\n";
-	count_str += TTR(" ObjectDB References: ") + String::num_uint64(objectdb_refs) + "\n";
-	count_str += TTR(" Total References: ") + String::num_uint64(total_refs) + "\n";
-	count_str += TTR(" ObjectDB Cycles: ") + String::num_uint64(ref_cycles.size()) + "\n";
+	count_str += vformat(TTRC("Native References: %d\n"), native_refs);
+	count_str += vformat(TTRC("ObjectDB References: %d\n"), objectdb_refs);
+	count_str += vformat(TTRC("Total References: %d\n"), total_refs);
+	count_str += vformat(TTRC("ObjectDB Cycles: %d\n"), ref_cycles.size());
 	count_str += "[/ul]\n";
 	count_str += "[/ul]\n";
 	RichTextLabel *counts = memnew(RichTextLabel(count_str));
 	RichTextLabel *counts = memnew(RichTextLabel(count_str));
 	counts->set_use_bbcode(true);
 	counts->set_use_bbcode(true);
@@ -223,7 +234,7 @@ void SnapshotRefCountedView::_refcounted_selected() {
 	properties_container->add_child(counts);
 	properties_container->add_child(counts);
 
 
 	if (d->inbound_references.size() > 0) {
 	if (d->inbound_references.size() > 0) {
-		RichTextLabel *inbound_lbl = memnew(RichTextLabel(TTR("[center]ObjectDB References[center]")));
+		RichTextLabel *inbound_lbl = memnew(RichTextLabel(TTRC("[center]ObjectDB References[center]")));
 		inbound_lbl->set_fit_content(true);
 		inbound_lbl->set_fit_content(true);
 		inbound_lbl->set_use_bbcode(true);
 		inbound_lbl->set_use_bbcode(true);
 		properties_container->add_child(inbound_lbl);
 		properties_container->add_child(inbound_lbl);
@@ -234,17 +245,17 @@ void SnapshotRefCountedView::_refcounted_selected() {
 		inbound_tree->set_hide_root(true);
 		inbound_tree->set_hide_root(true);
 		inbound_tree->set_columns(3);
 		inbound_tree->set_columns(3);
 		inbound_tree->set_column_titles_visible(true);
 		inbound_tree->set_column_titles_visible(true);
-		inbound_tree->set_column_title(0, TTR("Source"));
+		inbound_tree->set_column_title(0, TTRC("Source"));
 		inbound_tree->set_column_expand(0, true);
 		inbound_tree->set_column_expand(0, true);
 		inbound_tree->set_column_clip_content(0, false);
 		inbound_tree->set_column_clip_content(0, false);
-		inbound_tree->set_column_title_tooltip_text(0, TTR("Other object referencing this object"));
-		inbound_tree->set_column_title(1, TTR("Property"));
+		inbound_tree->set_column_title_tooltip_text(0, TTRC("Other object referencing this object"));
+		inbound_tree->set_column_title(1, TTRC("Property"));
 		inbound_tree->set_column_expand(1, true);
 		inbound_tree->set_column_expand(1, true);
 		inbound_tree->set_column_clip_content(1, true);
 		inbound_tree->set_column_clip_content(1, true);
-		inbound_tree->set_column_title_tooltip_text(1, TTR("Property of other object referencing this object"));
-		inbound_tree->set_column_title(2, TTR("Duplicate?"));
+		inbound_tree->set_column_title_tooltip_text(1, TTRC("Property of other object referencing this object"));
+		inbound_tree->set_column_title(2, TTRC("Duplicate?"));
 		inbound_tree->set_column_expand(2, false);
 		inbound_tree->set_column_expand(2, false);
-		inbound_tree->set_column_title_tooltip_text(2, TTR("Was the same reference returned by multiple getters on the source object?"));
+		inbound_tree->set_column_title_tooltip_text(2, TTRC("Was the same reference returned by multiple getters on the source object?"));
 		inbound_tree->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 		inbound_tree->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 		inbound_tree->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 		inbound_tree->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 		inbound_tree->set_v_scroll_enabled(false);
 		inbound_tree->set_v_scroll_enabled(false);
@@ -266,14 +277,16 @@ void SnapshotRefCountedView::_refcounted_selected() {
 			TreeItem *i = inbound_tree->create_item(root);
 			TreeItem *i = inbound_tree->create_item(root);
 			SnapshotDataObject *target = d->snapshot->objects[ob.value];
 			SnapshotDataObject *target = d->snapshot->objects[ob.value];
 			i->set_text(0, target->get_name());
 			i->set_text(0, target->get_name());
+			i->set_auto_translate_mode(0, AUTO_TRANSLATE_MODE_DISABLED);
 			i->set_text(1, ob.key);
 			i->set_text(1, ob.key);
-			i->set_text(2, property_repeat_count[ob.value] > 1 ? TTR("Yes") : TTR("No"));
+			i->set_auto_translate_mode(1, AUTO_TRANSLATE_MODE_DISABLED);
+			i->set_text(2, property_repeat_count[ob.value] > 1 ? TTRC("Yes") : TTRC("No"));
 			reference_item_map[i] = data_item_map[target];
 			reference_item_map[i] = data_item_map[target];
 		}
 		}
 	}
 	}
 
 
 	if (ref_cycles.size() > 0) {
 	if (ref_cycles.size() > 0) {
-		properties_container->add_child(memnew(SpanningHeader(TTR("ObjectDB Cycles"))));
+		properties_container->add_child(memnew(SpanningHeader(TTRC("ObjectDB Cycles"))));
 		Tree *cycles_tree = memnew(Tree);
 		Tree *cycles_tree = memnew(Tree);
 		cycles_tree->set_hide_folding(true);
 		cycles_tree->set_hide_folding(true);
 		properties_container->add_child(cycles_tree);
 		properties_container->add_child(cycles_tree);

+ 8 - 16
modules/objectdb_profiler/editor/data_viewers/shared_controls.cpp

@@ -56,7 +56,7 @@ DarkPanelContainer::DarkPanelContainer() {
 	Ref<StyleBoxFlat> content_wrapper_sbf;
 	Ref<StyleBoxFlat> content_wrapper_sbf;
 	content_wrapper_sbf.instantiate();
 	content_wrapper_sbf.instantiate();
 	content_wrapper_sbf->set_bg_color(EditorNode::get_singleton()->get_editor_theme()->get_color("dark_color_2", "Editor"));
 	content_wrapper_sbf->set_bg_color(EditorNode::get_singleton()->get_editor_theme()->get_color("dark_color_2", "Editor"));
-	add_theme_style_override("panel", content_wrapper_sbf);
+	add_theme_style_override(SceneStringName(panel), content_wrapper_sbf);
 }
 }
 
 
 void TreeSortAndFilterBar::_apply_filter(TreeItem *p_current_node) {
 void TreeSortAndFilterBar::_apply_filter(TreeItem *p_current_node) {
@@ -68,7 +68,7 @@ void TreeSortAndFilterBar::_apply_filter(TreeItem *p_current_node) {
 		return;
 		return;
 	}
 	}
 
 
-	// Reset ourself to default state.
+	// Reset ourselves to default state.
 	p_current_node->set_visible(true);
 	p_current_node->set_visible(true);
 	p_current_node->clear_custom_color(0);
 	p_current_node->clear_custom_color(0);
 
 
@@ -98,7 +98,7 @@ void TreeSortAndFilterBar::_apply_filter(TreeItem *p_current_node) {
 		// We have a visible child.
 		// We have a visible child.
 		p_current_node->set_custom_color(0, get_theme_color(SNAME("font_disabled_color"), EditorStringName(Editor)));
 		p_current_node->set_custom_color(0, get_theme_color(SNAME("font_disabled_color"), EditorStringName(Editor)));
 	} else {
 	} else {
-		// We and out children aren't visible.
+		// We and our children are not visible.
 		p_current_node->set_visible(false);
 		p_current_node->set_visible(false);
 	}
 	}
 }
 }
@@ -121,7 +121,8 @@ void TreeSortAndFilterBar::_apply_sort() {
 		TreeItem *to_sort = items_to_sort.front()->get();
 		TreeItem *to_sort = items_to_sort.front()->get();
 		items_to_sort.pop_front();
 		items_to_sort.pop_front();
 
 
-		List<TreeItemColumn> items;
+		LocalVector<TreeItemColumn> items;
+		items.reserve(to_sort->get_child_count());
 		for (int i = 0; i < to_sort->get_child_count(); i++) {
 		for (int i = 0; i < to_sort->get_child_count(); i++) {
 			items.push_back(TreeItemColumn(to_sort->get_child(i), sort.column));
 			items.push_back(TreeItemColumn(to_sort->get_child(i), sort.column));
 		}
 		}
@@ -187,15 +188,10 @@ TreeSortAndFilterBar::TreeSortAndFilterBar(Tree *p_managed_tree, const String &p
 void TreeSortAndFilterBar::_notification(int p_what) {
 void TreeSortAndFilterBar::_notification(int p_what) {
 	switch (p_what) {
 	switch (p_what) {
 		case NOTIFICATION_POSTINITIALIZE:
 		case NOTIFICATION_POSTINITIALIZE:
-		case NOTIFICATION_ENTER_TREE:
-		case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
-		case NOTIFICATION_THEME_CHANGED:
-		case NOTIFICATION_TRANSLATION_CHANGED: {
+		case NOTIFICATION_THEME_CHANGED: {
 			filter_edit->set_right_icon(get_editor_theme_icon(SNAME("Search")));
 			filter_edit->set_right_icon(get_editor_theme_icon(SNAME("Search")));
 			sort_button->set_button_icon(get_editor_theme_icon(SNAME("Sort")));
 			sort_button->set_button_icon(get_editor_theme_icon(SNAME("Sort")));
-
 			apply();
 			apply();
-
 		} break;
 		} break;
 	}
 	}
 }
 }
@@ -203,11 +199,11 @@ void TreeSortAndFilterBar::_notification(int p_what) {
 TreeSortAndFilterBar::SortOptionIndexes TreeSortAndFilterBar::add_sort_option(const String &p_new_option, SortType p_sort_type, int p_sort_column, bool p_is_default) {
 TreeSortAndFilterBar::SortOptionIndexes TreeSortAndFilterBar::add_sort_option(const String &p_new_option, SortType p_sort_type, int p_sort_column, bool p_is_default) {
 	sort_button->set_visible(true);
 	sort_button->set_visible(true);
 	bool is_first_item = sort_items.is_empty();
 	bool is_first_item = sort_items.is_empty();
-	SortItem item_ascending(sort_items.size(), TTR("Sort By ") + p_new_option + TTR(" (Ascending)"), p_sort_type, true, p_sort_column);
+	SortItem item_ascending(sort_items.size(), vformat(TTRC("Sort By %s (Ascending)"), p_new_option), p_sort_type, true, p_sort_column);
 	sort_items[item_ascending.id] = item_ascending;
 	sort_items[item_ascending.id] = item_ascending;
 	sort_button->get_popup()->add_radio_check_item(item_ascending.label, item_ascending.id);
 	sort_button->get_popup()->add_radio_check_item(item_ascending.label, item_ascending.id);
 
 
-	SortItem item_descending(sort_items.size(), TTR("Sort By ") + p_new_option + TTR(" (Descending)"), p_sort_type, false, p_sort_column);
+	SortItem item_descending(sort_items.size(), vformat(TTRC("Sort By %s (Descending)"), p_new_option), p_sort_type, false, p_sort_column);
 	sort_items[item_descending.id] = item_descending;
 	sort_items[item_descending.id] = item_descending;
 	sort_button->get_popup()->add_radio_check_item(item_descending.label, item_descending.id);
 	sort_button->get_popup()->add_radio_check_item(item_descending.label, item_descending.id);
 
 
@@ -240,10 +236,6 @@ void TreeSortAndFilterBar::apply() {
 		return;
 		return;
 	}
 	}
 
 
-	OS::get_singleton()->benchmark_begin_measure("odb profiler", "TreeSortAndFilterBar::apply _apply_sort");
 	_apply_sort();
 	_apply_sort();
-	OS::get_singleton()->benchmark_end_measure("odb profiler", "TreeSortAndFilterBar::apply _apply_sort");
-	OS::get_singleton()->benchmark_begin_measure("odb profiler", "TreeSortAndFilterBar::apply _apply_filter");
 	_apply_filter();
 	_apply_filter();
-	OS::get_singleton()->benchmark_end_measure("odb profiler", "TreeSortAndFilterBar::apply _apply_filter");
 }
 }

+ 2 - 2
modules/objectdb_profiler/editor/data_viewers/snapshot_view.cpp

@@ -50,8 +50,8 @@ bool SnapshotView::is_showing_snapshot(GameStateSnapshot *p_data, GameStateSnaps
 	return p_data == snapshot_data && p_diff_data == diff_data;
 	return p_data == snapshot_data && p_diff_data == diff_data;
 }
 }
 
 
-List<TreeItem *> SnapshotView::_get_children_recursive(Tree *p_tree) {
-	List<TreeItem *> found_items;
+Vector<TreeItem *> SnapshotView::_get_children_recursive(Tree *p_tree) {
+	Vector<TreeItem *> found_items;
 	List<TreeItem *> items_to_check;
 	List<TreeItem *> items_to_check;
 	if (p_tree && p_tree->get_root()) {
 	if (p_tree && p_tree->get_root()) {
 		items_to_check.push_back(p_tree->get_root());
 		items_to_check.push_back(p_tree->get_root());

+ 1 - 1
modules/objectdb_profiler/editor/data_viewers/snapshot_view.h

@@ -44,7 +44,7 @@ protected:
 	GameStateSnapshot *snapshot_data = nullptr;
 	GameStateSnapshot *snapshot_data = nullptr;
 	GameStateSnapshot *diff_data = nullptr;
 	GameStateSnapshot *diff_data = nullptr;
 
 
-	List<TreeItem *> _get_children_recursive(Tree *p_tree);
+	Vector<TreeItem *> _get_children_recursive(Tree *p_tree);
 
 
 public:
 public:
 	String view_name;
 	String view_name;

+ 29 - 27
modules/objectdb_profiler/editor/data_viewers/summary_view.cpp

@@ -39,7 +39,7 @@
 #include "scene/resources/style_box_flat.h"
 #include "scene/resources/style_box_flat.h"
 
 
 SnapshotSummaryView::SnapshotSummaryView() {
 SnapshotSummaryView::SnapshotSummaryView() {
-	set_name("Summary");
+	set_name(TTRC("Summary"));
 
 
 	set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 	set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 	set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 	set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
@@ -70,7 +70,7 @@ SnapshotSummaryView::SnapshotSummaryView() {
 	pc->add_theme_style_override("panel", sbf);
 	pc->add_theme_style_override("panel", sbf);
 	content->add_child(pc);
 	content->add_child(pc);
 	pc->set_anchors_preset(LayoutPreset::PRESET_TOP_WIDE);
 	pc->set_anchors_preset(LayoutPreset::PRESET_TOP_WIDE);
-	Label *title = memnew(Label(TTR("ObjectDB Snapshot Summary")));
+	Label *title = memnew(Label(TTRC("ObjectDB Snapshot Summary")));
 	pc->add_child(title);
 	pc->add_child(title);
 	title->set_horizontal_alignment(HorizontalAlignment::HORIZONTAL_ALIGNMENT_CENTER);
 	title->set_horizontal_alignment(HorizontalAlignment::HORIZONTAL_ALIGNMENT_CENTER);
 	title->set_vertical_alignment(VerticalAlignment::VERTICAL_ALIGNMENT_CENTER);
 	title->set_vertical_alignment(VerticalAlignment::VERTICAL_ALIGNMENT_CENTER);
@@ -81,9 +81,9 @@ SnapshotSummaryView::SnapshotSummaryView() {
 	content->add_child(explainer_text);
 	content->add_child(explainer_text);
 	VBoxContainer *explainer_lines = memnew(VBoxContainer);
 	VBoxContainer *explainer_lines = memnew(VBoxContainer);
 	explainer_text->add_child(explainer_lines);
 	explainer_text->add_child(explainer_lines);
-	Label *l1 = memnew(Label(TTR("Press 'Take ObjectDB Snapshot' to snapshot the ObjectDB.")));
-	Label *l2 = memnew(Label(TTR("Memory in Godot is either owned natively by the engine or owned by the ObjectDB.")));
-	Label *l3 = memnew(Label(TTR("ObjectDB Snapshots capture only memory owned by the ObjectDB.")));
+	Label *l1 = memnew(Label(TTRC("Press 'Take ObjectDB Snapshot' to snapshot the ObjectDB.")));
+	Label *l2 = memnew(Label(TTRC("Memory in Godot is either owned natively by the engine or owned by the ObjectDB.")));
+	Label *l3 = memnew(Label(TTRC("ObjectDB Snapshots capture only memory owned by the ObjectDB.")));
 	l1->set_horizontal_alignment(HorizontalAlignment::HORIZONTAL_ALIGNMENT_CENTER);
 	l1->set_horizontal_alignment(HorizontalAlignment::HORIZONTAL_ALIGNMENT_CENTER);
 	l2->set_horizontal_alignment(HorizontalAlignment::HORIZONTAL_ALIGNMENT_CENTER);
 	l2->set_horizontal_alignment(HorizontalAlignment::HORIZONTAL_ALIGNMENT_CENTER);
 	l3->set_horizontal_alignment(HorizontalAlignment::HORIZONTAL_ALIGNMENT_CENTER);
 	l3->set_horizontal_alignment(HorizontalAlignment::HORIZONTAL_ALIGNMENT_CENTER);
@@ -107,27 +107,27 @@ void SnapshotSummaryView::show_snapshot(GameStateSnapshot *p_data, GameStateSnap
 	SnapshotView::show_snapshot(p_data, p_diff_data);
 	SnapshotView::show_snapshot(p_data, p_diff_data);
 	explainer_text->set_visible(false);
 	explainer_text->set_visible(false);
 
 
-	String snapshot_a_name = diff_data == nullptr ? TTR("Snapshot") : TTR("Snapshot A");
-	String snapshot_b_name = TTR("Snapshot B");
+	String snapshot_a_name = diff_data == nullptr ? TTRC("Snapshot") : TTRC("Snapshot A");
+	String snapshot_b_name = TTRC("Snapshot B");
 
 
-	_push_overview_blurb(snapshot_a_name + " " + TTR("Overview"), snapshot_data);
+	_push_overview_blurb(snapshot_a_name + " " + TTRC("Overview"), snapshot_data);
 	if (diff_data) {
 	if (diff_data) {
-		_push_overview_blurb(snapshot_b_name + " " + TTR("Overview"), diff_data);
+		_push_overview_blurb(snapshot_b_name + " " + TTRC("Overview"), diff_data);
 	}
 	}
 
 
-	_push_node_blurb(snapshot_a_name + " " + TTR("Nodes"), snapshot_data);
+	_push_node_blurb(snapshot_a_name + " " + TTRC("Nodes"), snapshot_data);
 	if (diff_data) {
 	if (diff_data) {
-		_push_node_blurb(snapshot_b_name + " " + TTR("Nodes"), diff_data);
+		_push_node_blurb(snapshot_b_name + " " + TTRC("Nodes"), diff_data);
 	}
 	}
 
 
-	_push_refcounted_blurb(snapshot_a_name + " " + TTR("RefCounteds"), snapshot_data);
+	_push_refcounted_blurb(snapshot_a_name + " " + TTRC("RefCounteds"), snapshot_data);
 	if (diff_data) {
 	if (diff_data) {
-		_push_refcounted_blurb(snapshot_b_name + " " + TTR("RefCounteds"), diff_data);
+		_push_refcounted_blurb(snapshot_b_name + " " + TTRC("RefCounteds"), diff_data);
 	}
 	}
 
 
-	_push_object_blurb(snapshot_a_name + " " + TTR("Objects"), snapshot_data);
+	_push_object_blurb(snapshot_a_name + " " + TTRC("Objects"), snapshot_data);
 	if (diff_data) {
 	if (diff_data) {
-		_push_object_blurb(snapshot_b_name + " " + TTR("Objects"), diff_data);
+		_push_object_blurb(snapshot_b_name + " " + TTRC("Objects"), diff_data);
 	}
 	}
 }
 }
 
 
@@ -149,6 +149,7 @@ SummaryBlurb::SummaryBlurb(const String &p_title, const String &p_rtl_content) {
 
 
 	label = memnew(RichTextLabel);
 	label = memnew(RichTextLabel);
 	label->add_theme_constant_override(SceneStringName(line_separation), 6);
 	label->add_theme_constant_override(SceneStringName(line_separation), 6);
+	label->set_text_direction(Control::TEXT_DIRECTION_INHERITED);
 	label->set_fit_content(true);
 	label->set_fit_content(true);
 	label->set_use_bbcode(true);
 	label->set_use_bbcode(true);
 	label->add_newline();
 	label->add_newline();
@@ -183,11 +184,6 @@ void SnapshotSummaryView::_push_overview_blurb(const String &p_title, GameStateS
 	if (p_snapshot->snapshot_context.has("mem_max_usage")) {
 	if (p_snapshot->snapshot_context.has("mem_max_usage")) {
 		c += vformat(" [i]%s[/i] %s\n", TTR("Max Memory Used:"), String::num((double)((uint64_t)p_snapshot->snapshot_context["mem_max_usage"]) * bytes_to_mb, 3) + " MB");
 		c += vformat(" [i]%s[/i] %s\n", TTR("Max Memory Used:"), String::num((double)((uint64_t)p_snapshot->snapshot_context["mem_max_usage"]) * bytes_to_mb, 3) + " MB");
 	}
 	}
-	if (p_snapshot->snapshot_context.has("mem_available")) {
-		// I'm guessing pretty hard about what this is supposed to be. It's hard coded to be -1 cast to a uint64_t in Memory.h,
-		// so it _could_ be checking if we're on a 64 bit system, I think...
-		c += vformat(" [i]%s[/i] %s\n", TTR("Max uint64 Value:"), String::num_uint64((uint64_t)p_snapshot->snapshot_context["mem_available"]));
-	}
 	c += vformat(" [i]%s[/i] %s\n", TTR("Total Objects:"), itos(p_snapshot->objects.size()));
 	c += vformat(" [i]%s[/i] %s\n", TTR("Total Objects:"), itos(p_snapshot->objects.size()));
 
 
 	int node_count = 0;
 	int node_count = 0;
@@ -203,11 +199,13 @@ void SnapshotSummaryView::_push_overview_blurb(const String &p_title, GameStateS
 }
 }
 
 
 void SnapshotSummaryView::_push_node_blurb(const String &p_title, GameStateSnapshot *p_snapshot) {
 void SnapshotSummaryView::_push_node_blurb(const String &p_title, GameStateSnapshot *p_snapshot) {
-	List<String> nodes;
+	LocalVector<String> nodes;
+	nodes.reserve(p_snapshot->objects.size());
+
 	for (const KeyValue<ObjectID, SnapshotDataObject *> &pair : p_snapshot->objects) {
 	for (const KeyValue<ObjectID, SnapshotDataObject *> &pair : p_snapshot->objects) {
 		// if it's a node AND it doesn't have a parent node
 		// if it's a node AND it doesn't have a parent node
 		if (pair.value->is_node() && !pair.value->extra_debug_data.has("node_parent") && pair.value->extra_debug_data.has("node_is_scene_root") && !pair.value->extra_debug_data["node_is_scene_root"]) {
 		if (pair.value->is_node() && !pair.value->extra_debug_data.has("node_parent") && pair.value->extra_debug_data.has("node_is_scene_root") && !pair.value->extra_debug_data["node_is_scene_root"]) {
-			const String &node_name = pair.value->extra_debug_data["node_name"];
+			String node_name = pair.value->extra_debug_data["node_name"];
 			nodes.push_back(node_name != "" ? node_name : pair.value->get_name());
 			nodes.push_back(node_name != "" ? node_name : pair.value->get_name());
 		}
 		}
 	}
 	}
@@ -216,7 +214,7 @@ void SnapshotSummaryView::_push_node_blurb(const String &p_title, GameStateSnaps
 		return;
 		return;
 	}
 	}
 
 
-	String c = TTR("Multiple root nodes [i](possible call to 'remove_child' without 'queue_free')[/i]\n");
+	String c = TTRC("Multiple root nodes [i](possible call to 'remove_child' without 'queue_free')[/i]\n");
 	c += "[ul]\n";
 	c += "[ul]\n";
 	for (const String &node : nodes) {
 	for (const String &node : nodes) {
 		c += " " + node + "\n";
 		c += " " + node + "\n";
@@ -227,7 +225,9 @@ void SnapshotSummaryView::_push_node_blurb(const String &p_title, GameStateSnaps
 }
 }
 
 
 void SnapshotSummaryView::_push_refcounted_blurb(const String &p_title, GameStateSnapshot *p_snapshot) {
 void SnapshotSummaryView::_push_refcounted_blurb(const String &p_title, GameStateSnapshot *p_snapshot) {
-	List<String> rcs;
+	LocalVector<String> rcs;
+	rcs.reserve(p_snapshot->objects.size());
+
 	for (const KeyValue<ObjectID, SnapshotDataObject *> &pair : p_snapshot->objects) {
 	for (const KeyValue<ObjectID, SnapshotDataObject *> &pair : p_snapshot->objects) {
 		if (pair.value->is_refcounted()) {
 		if (pair.value->is_refcounted()) {
 			int ref_count = (uint64_t)pair.value->extra_debug_data["ref_count"];
 			int ref_count = (uint64_t)pair.value->extra_debug_data["ref_count"];
@@ -243,7 +243,7 @@ void SnapshotSummaryView::_push_refcounted_blurb(const String &p_title, GameStat
 		return;
 		return;
 	}
 	}
 
 
-	String c = TTR("RefCounted objects only referenced in cycles [i](cycles often indicate a memory leaks)[/i]\n");
+	String c = TTRC("RefCounted objects only referenced in cycles [i](cycles often indicate a memory leaks)[/i]\n");
 	c += "[ul]\n";
 	c += "[ul]\n";
 	for (const String &rc : rcs) {
 	for (const String &rc : rcs) {
 		c += " " + rc + "\n";
 		c += " " + rc + "\n";
@@ -254,7 +254,9 @@ void SnapshotSummaryView::_push_refcounted_blurb(const String &p_title, GameStat
 }
 }
 
 
 void SnapshotSummaryView::_push_object_blurb(const String &p_title, GameStateSnapshot *p_snapshot) {
 void SnapshotSummaryView::_push_object_blurb(const String &p_title, GameStateSnapshot *p_snapshot) {
-	List<String> objects;
+	LocalVector<String> objects;
+	objects.reserve(p_snapshot->objects.size());
+
 	for (const KeyValue<ObjectID, SnapshotDataObject *> &pair : p_snapshot->objects) {
 	for (const KeyValue<ObjectID, SnapshotDataObject *> &pair : p_snapshot->objects) {
 		if (pair.value->inbound_references.is_empty() && pair.value->outbound_references.is_empty()) {
 		if (pair.value->inbound_references.is_empty() && pair.value->outbound_references.is_empty()) {
 			if (!pair.value->get_script().is_null()) {
 			if (!pair.value->get_script().is_null()) {
@@ -271,7 +273,7 @@ void SnapshotSummaryView::_push_object_blurb(const String &p_title, GameStateSna
 		return;
 		return;
 	}
 	}
 
 
-	String c = TTR("Scripted objects not referenced by any other objects [i](unreferenced objects may indicate a memory leak)[/i]\n");
+	String c = TTRC("Scripted objects not referenced by any other objects [i](unreferenced objects may indicate a memory leak)[/i]\n");
 	c += "[ul]\n";
 	c += "[ul]\n";
 	for (const String &object : objects) {
 	for (const String &object : objects) {
 		c += " " + object + "\n";
 		c += " " + object + "\n";

+ 100 - 81
modules/objectdb_profiler/editor/objectdb_profiler_panel.cpp

@@ -32,7 +32,6 @@
 
 
 #include "../snapshot_collector.h"
 #include "../snapshot_collector.h"
 #include "data_viewers/class_view.h"
 #include "data_viewers/class_view.h"
-#include "data_viewers/json_view.h"
 #include "data_viewers/node_view.h"
 #include "data_viewers/node_view.h"
 #include "data_viewers/object_view.h"
 #include "data_viewers/object_view.h"
 #include "data_viewers/refcounted_view.h"
 #include "data_viewers/refcounted_view.h"
@@ -56,7 +55,7 @@ const int SNAPSHOT_CHUNK_SIZE = 6 << 20;
 
 
 void ObjectDBProfilerPanel::_request_object_snapshot() {
 void ObjectDBProfilerPanel::_request_object_snapshot() {
 	take_snapshot->set_disabled(true);
 	take_snapshot->set_disabled(true);
-	take_snapshot->set_text(TTR("Generating Snapshot"));
+	take_snapshot->set_text(TTRC("Generating Snapshot"));
 	// Pause the game while the snapshot is taken so the state of the game isn't modified as we capture the snapshot.
 	// Pause the game while the snapshot is taken so the state of the game isn't modified as we capture the snapshot.
 	if (EditorDebuggerNode::get_singleton()->get_current_debugger()->is_breaked()) {
 	if (EditorDebuggerNode::get_singleton()->get_current_debugger()->is_breaked()) {
 		requested_break_for_snapshot = false;
 		requested_break_for_snapshot = false;
@@ -76,42 +75,34 @@ void ObjectDBProfilerPanel::_on_debug_breaked(bool p_reallydid, bool p_can_debug
 }
 }
 
 
 void ObjectDBProfilerPanel::_begin_object_snapshot() {
 void ObjectDBProfilerPanel::_begin_object_snapshot() {
-	Array args;
-	args.push_back(next_request_id++);
-	args.push_back(SnapshotCollector::get_godot_version_string());
+	Array args = { next_request_id++, SnapshotCollector::get_godot_version_string() };
 	EditorDebuggerNode::get_singleton()->get_current_debugger()->send_message("snapshot:request_prepare_snapshot", args);
 	EditorDebuggerNode::get_singleton()->get_current_debugger()->send_message("snapshot:request_prepare_snapshot", args);
 }
 }
 
 
 bool ObjectDBProfilerPanel::handle_debug_message(const String &p_message, const Array &p_data, int p_index) {
 bool ObjectDBProfilerPanel::handle_debug_message(const String &p_message, const Array &p_data, int p_index) {
 	if (p_message == "snapshot:snapshot_prepared") {
 	if (p_message == "snapshot:snapshot_prepared") {
-		int request_id = p_data.get(0);
-		int total_size = p_data.get(1);
+		int request_id = p_data[0];
+		int total_size = p_data[1];
 		partial_snapshots[request_id] = PartialSnapshot();
 		partial_snapshots[request_id] = PartialSnapshot();
 		partial_snapshots[request_id].total_size = total_size;
 		partial_snapshots[request_id].total_size = total_size;
-		Array args;
-		args.push_back(request_id);
-		args.push_back(0);
-		args.push_back(SNAPSHOT_CHUNK_SIZE);
-		take_snapshot->set_text(TTR("Receiving Snapshot") + " (0/" + _to_mb(total_size) + " mb)");
+		Array args = { request_id, 0, SNAPSHOT_CHUNK_SIZE };
+		take_snapshot->set_text(vformat(TTRC("Receiving Snapshot (0/%s MiB)"), _to_mb(total_size)));
 		EditorDebuggerNode::get_singleton()->get_current_debugger()->send_message("snapshot:request_snapshot_chunk", args);
 		EditorDebuggerNode::get_singleton()->get_current_debugger()->send_message("snapshot:request_snapshot_chunk", args);
 		return true;
 		return true;
 	}
 	}
 	if (p_message == "snapshot:snapshot_chunk") {
 	if (p_message == "snapshot:snapshot_chunk") {
-		int request_id = p_data.get(0);
+		int request_id = p_data[0];
 		PartialSnapshot &chunk = partial_snapshots[request_id];
 		PartialSnapshot &chunk = partial_snapshots[request_id];
-		chunk.data.append_array(p_data.get(1));
-		take_snapshot->set_text(TTR("Receiving Snapshot") + " (" + _to_mb(chunk.data.size()) + "/" + _to_mb(chunk.total_size) + " mb)");
+		chunk.data.append_array(p_data[1]);
+		take_snapshot->set_text(vformat(TTRC("Receiving Snapshot (%s/%s MiB)"), _to_mb(chunk.data.size()), _to_mb(chunk.total_size)));
 		if (chunk.data.size() != chunk.total_size) {
 		if (chunk.data.size() != chunk.total_size) {
-			Array args;
-			args.push_back(request_id);
-			args.push_back(chunk.data.size());
-			args.push_back(chunk.data.size() + SNAPSHOT_CHUNK_SIZE);
+			Array args = { request_id, chunk.data.size(), chunk.data.size() + SNAPSHOT_CHUNK_SIZE };
 			EditorDebuggerNode::get_singleton()->get_current_debugger()->send_message("snapshot:request_snapshot_chunk", args);
 			EditorDebuggerNode::get_singleton()->get_current_debugger()->send_message("snapshot:request_snapshot_chunk", args);
 			return true;
 			return true;
 		}
 		}
 
 
-		take_snapshot->set_text(TTR("Visualizing Snapshot"));
-		// Wait a frame just so the button has a chance to update it's text so the user knows what's going on.
+		take_snapshot->set_text(TTRC("Visualizing Snapshot"));
+		// Wait a frame just so the button has a chance to update its text so the user knows what's going on.
 		get_tree()->connect("process_frame", callable_mp(this, &ObjectDBProfilerPanel::receive_snapshot).bind(request_id), CONNECT_ONE_SHOT);
 		get_tree()->connect("process_frame", callable_mp(this, &ObjectDBProfilerPanel::receive_snapshot).bind(request_id), CONNECT_ONE_SHOT);
 		return true;
 		return true;
 	}
 	}
@@ -120,7 +111,7 @@ bool ObjectDBProfilerPanel::handle_debug_message(const String &p_message, const
 
 
 void ObjectDBProfilerPanel::receive_snapshot(int request_id) {
 void ObjectDBProfilerPanel::receive_snapshot(int request_id) {
 	const Vector<uint8_t> &in_data = partial_snapshots[request_id].data;
 	const Vector<uint8_t> &in_data = partial_snapshots[request_id].data;
-	String snapshot_file_name = Time::get_singleton()->get_datetime_string_from_system(false).replace("T", "_").replace(":", "-");
+	String snapshot_file_name = Time::get_singleton()->get_datetime_string_from_system(false).replace_char('T', '_').replace_char(':', '-');
 	Ref<DirAccess> snapshot_dir = _get_and_create_snapshot_storage_dir();
 	Ref<DirAccess> snapshot_dir = _get_and_create_snapshot_storage_dir();
 	if (snapshot_dir.is_valid()) {
 	if (snapshot_dir.is_valid()) {
 		Error err;
 		Error err;
@@ -166,13 +157,15 @@ TreeItem *ObjectDBProfilerPanel::_add_snapshot_button(const String &p_snapshot_f
 	TreeItem *item = snapshot_list->create_item(snapshot_list->get_root());
 	TreeItem *item = snapshot_list->create_item(snapshot_list->get_root());
 	item->set_text(0, p_snapshot_file_name);
 	item->set_text(0, p_snapshot_file_name);
 	item->set_metadata(0, p_full_file_path);
 	item->set_metadata(0, p_full_file_path);
+	item->set_auto_translate_mode(0, AUTO_TRANSLATE_MODE_DISABLED);
 	item->move_before(snapshot_list->get_root()->get_first_child());
 	item->move_before(snapshot_list->get_root()->get_first_child());
 	_update_diff_items();
 	_update_diff_items();
+	_update_enabled_diff_items();
 	return item;
 	return item;
 }
 }
 
 
 void ObjectDBProfilerPanel::_show_selected_snapshot() {
 void ObjectDBProfilerPanel::_show_selected_snapshot() {
-	if (snapshot_list->get_selected()->get_text(0) == diff_options[diff_button->get_selected_id()]) {
+	if (snapshot_list->get_selected()->get_text(0) == (String)diff_button->get_selected_metadata()) {
 		for (int i = 0; i < diff_button->get_item_count(); i++) {
 		for (int i = 0; i < diff_button->get_item_count(); i++) {
 			if (diff_button->get_item_text(i) == current_snapshot->get_snapshot()->name) {
 			if (diff_button->get_item_text(i) == current_snapshot->get_snapshot()->name) {
 				diff_button->select(i);
 				diff_button->select(i);
@@ -180,51 +173,57 @@ void ObjectDBProfilerPanel::_show_selected_snapshot() {
 			}
 			}
 		}
 		}
 	}
 	}
-	show_snapshot(snapshot_list->get_selected()->get_text(0), diff_options[diff_button->get_selected_id()]);
+	show_snapshot(snapshot_list->get_selected()->get_text(0), diff_button->get_selected_metadata());
+	_update_enabled_diff_items();
+}
+
+void ObjectDBProfilerPanel::_on_snapshot_deselected() {
+	snapshot_list->deselect_all();
+	diff_button->select(0);
+	clear_snapshot();
 	_update_enabled_diff_items();
 	_update_enabled_diff_items();
 }
 }
 
 
 Ref<GameStateSnapshotRef> ObjectDBProfilerPanel::get_snapshot(const String &p_snapshot_file_name) {
 Ref<GameStateSnapshotRef> ObjectDBProfilerPanel::get_snapshot(const String &p_snapshot_file_name) {
 	if (snapshot_cache.has(p_snapshot_file_name)) {
 	if (snapshot_cache.has(p_snapshot_file_name)) {
 		return snapshot_cache.get(p_snapshot_file_name);
 		return snapshot_cache.get(p_snapshot_file_name);
-	} else {
-		Ref<DirAccess> snapshot_dir = _get_and_create_snapshot_storage_dir();
-		ERR_FAIL_COND_V_MSG(snapshot_dir.is_null(), nullptr, "Could not access ObjectDB Snapshot directory");
+	}
 
 
-		String full_file_path = snapshot_dir->get_current_dir().path_join(p_snapshot_file_name) + ".odb_snapshot";
+	Ref<DirAccess> snapshot_dir = _get_and_create_snapshot_storage_dir();
+	ERR_FAIL_COND_V_MSG(snapshot_dir.is_null(), nullptr, "Could not access ObjectDB Snapshot directory");
 
 
-		Error err;
-		Ref<FileAccess> snapshot_file = FileAccess::open(full_file_path, FileAccess::READ, &err);
-		ERR_FAIL_COND_V_MSG(err != OK, nullptr, "Could not open ObjectDB Snapshot file: " + full_file_path);
+	String full_file_path = snapshot_dir->get_current_dir().path_join(p_snapshot_file_name) + ".odb_snapshot";
 
 
-		Vector<uint8_t> content = snapshot_file->get_buffer(snapshot_file->get_length()); // We want to split on newlines, so normalize them.
-		ERR_FAIL_COND_V_MSG(content.is_empty(), nullptr, "ObjectDB Snapshot file is empty: " + full_file_path);
+	Error err;
+	Ref<FileAccess> snapshot_file = FileAccess::open(full_file_path, FileAccess::READ, &err);
+	ERR_FAIL_COND_V_MSG(err != OK, nullptr, "Could not open ObjectDB Snapshot file: " + full_file_path);
 
 
-		Ref<GameStateSnapshotRef> snapshot = GameStateSnapshot::create_ref(p_snapshot_file_name, content);
-		if (snapshot.is_valid()) {
-			// Don't cache a null snapshot.
-			snapshot_cache.insert(p_snapshot_file_name, snapshot);
-		}
-		return snapshot;
+	Vector<uint8_t> content = snapshot_file->get_buffer(snapshot_file->get_length()); // We want to split on newlines, so normalize them.
+	ERR_FAIL_COND_V_MSG(content.is_empty(), nullptr, "ObjectDB Snapshot file is empty: " + full_file_path);
+
+	Ref<GameStateSnapshotRef> snapshot = GameStateSnapshot::create_ref(p_snapshot_file_name, content);
+	if (snapshot.is_valid()) {
+		snapshot_cache.insert(p_snapshot_file_name, snapshot);
 	}
 	}
+
+	return snapshot;
 }
 }
 
 
 void ObjectDBProfilerPanel::show_snapshot(const String &p_snapshot_file_name, const String &p_snapshot_diff_file_name) {
 void ObjectDBProfilerPanel::show_snapshot(const String &p_snapshot_file_name, const String &p_snapshot_diff_file_name) {
-	clear_snapshot();
+	clear_snapshot(false);
 
 
 	current_snapshot = get_snapshot(p_snapshot_file_name);
 	current_snapshot = get_snapshot(p_snapshot_file_name);
-	if (p_snapshot_diff_file_name != "none") {
+	if (!p_snapshot_diff_file_name.is_empty()) {
 		diff_snapshot = get_snapshot(p_snapshot_diff_file_name);
 		diff_snapshot = get_snapshot(p_snapshot_diff_file_name);
-	} else {
-		diff_snapshot.unref();
 	}
 	}
 
 
+	_update_view_tabs();
 	_view_tab_changed(view_tabs->get_current_tab());
 	_view_tab_changed(view_tabs->get_current_tab());
 }
 }
 
 
 void ObjectDBProfilerPanel::_view_tab_changed(int p_tab_idx) {
 void ObjectDBProfilerPanel::_view_tab_changed(int p_tab_idx) {
 	// Populating tabs only on tab changed because we're handling a lot of data,
 	// Populating tabs only on tab changed because we're handling a lot of data,
-	// and the editor freezes for while if we try to populate every tab at once.
+	// and the editor freezes for a while if we try to populate every tab at once.
 	SnapshotView *view = cast_to<SnapshotView>(view_tabs->get_current_tab_control());
 	SnapshotView *view = cast_to<SnapshotView>(view_tabs->get_current_tab_control());
 	GameStateSnapshot *snapshot = current_snapshot.is_null() ? nullptr : current_snapshot->get_snapshot();
 	GameStateSnapshot *snapshot = current_snapshot.is_null() ? nullptr : current_snapshot->get_snapshot();
 	GameStateSnapshot *diff = diff_snapshot.is_null() ? nullptr : diff_snapshot->get_snapshot();
 	GameStateSnapshot *diff = diff_snapshot.is_null() ? nullptr : diff_snapshot->get_snapshot();
@@ -233,15 +232,21 @@ void ObjectDBProfilerPanel::_view_tab_changed(int p_tab_idx) {
 	}
 	}
 }
 }
 
 
-void ObjectDBProfilerPanel::clear_snapshot() {
+void ObjectDBProfilerPanel::clear_snapshot(bool p_update_view_tabs) {
 	for (SnapshotView *view : views) {
 	for (SnapshotView *view : views) {
 		view->clear_snapshot();
 		view->clear_snapshot();
 	}
 	}
+
 	current_snapshot.unref();
 	current_snapshot.unref();
+	diff_snapshot.unref();
+
+	if (p_update_view_tabs) {
+		_update_view_tabs();
+	}
 }
 }
 
 
 void ObjectDBProfilerPanel::set_enabled(bool p_enabled) {
 void ObjectDBProfilerPanel::set_enabled(bool p_enabled) {
-	take_snapshot->set_text(TTR("Take ObjectDB Snapshot"));
+	take_snapshot->set_text(TTRC("Take ObjectDB Snapshot"));
 	take_snapshot->set_disabled(!p_enabled);
 	take_snapshot->set_disabled(!p_enabled);
 }
 }
 
 
@@ -251,12 +256,12 @@ void ObjectDBProfilerPanel::_snapshot_rmb(const Vector2 &p_pos, MouseButton p_bu
 	}
 	}
 	rmb_menu->clear(false);
 	rmb_menu->clear(false);
 
 
-	rmb_menu->add_icon_item(get_editor_theme_icon(SNAME("Rename")), TTR("Rename Snapshot"), OdbProfilerMenuOptions::ODB_MENU_RENAME);
-	rmb_menu->add_icon_item(get_editor_theme_icon(SNAME("Folder")), TTR("Show in Folder"), OdbProfilerMenuOptions::ODB_MENU_SHOW_IN_FOLDER);
-	rmb_menu->add_icon_item(get_editor_theme_icon(SNAME("Remove")), TTR("Delete Snapshot"), OdbProfilerMenuOptions::ODB_MENU_DELETE);
+	rmb_menu->add_icon_item(get_editor_theme_icon(SNAME("Rename")), TTRC("Rename"), OdbProfilerMenuOptions::ODB_MENU_RENAME);
+	rmb_menu->add_icon_item(get_editor_theme_icon(SNAME("Folder")), TTRC("Show in File Manager"), OdbProfilerMenuOptions::ODB_MENU_SHOW_IN_FOLDER);
+	rmb_menu->add_icon_item(get_editor_theme_icon(SNAME("Remove")), TTRC("Delete"), OdbProfilerMenuOptions::ODB_MENU_DELETE);
 
 
+	rmb_menu->set_position(snapshot_list->get_screen_position() + p_pos);
 	rmb_menu->reset_size();
 	rmb_menu->reset_size();
-	rmb_menu->set_position(get_screen_position() + p_pos);
 	rmb_menu->popup();
 	rmb_menu->popup();
 }
 }
 
 
@@ -275,7 +280,6 @@ void ObjectDBProfilerPanel::_rmb_menu_pressed(int p_tool, bool p_confirm_overrid
 				snapshot_list->set_selected(snapshot_list->get_root()->get_first_child());
 				snapshot_list->set_selected(snapshot_list->get_root()->get_first_child());
 			} else {
 			} else {
 				// If we deleted the last snapshot, jump back to the summary tab and clear everything out.
 				// If we deleted the last snapshot, jump back to the summary tab and clear everything out.
-				view_tabs->set_current_tab(0);
 				clear_snapshot();
 				clear_snapshot();
 			}
 			}
 			_update_diff_items();
 			_update_diff_items();
@@ -289,13 +293,13 @@ void ObjectDBProfilerPanel::_rmb_menu_pressed(int p_tool, bool p_confirm_overrid
 }
 }
 
 
 void ObjectDBProfilerPanel::_edit_snapshot_name() {
 void ObjectDBProfilerPanel::_edit_snapshot_name() {
-	const String &new_snapshot_name = snapshot_list->get_selected()->get_text(0);
-	const String &full_file_with_path = snapshot_list->get_selected()->get_metadata(0);
+	String new_snapshot_name = snapshot_list->get_selected()->get_text(0);
+	String full_file_with_path = snapshot_list->get_selected()->get_metadata(0);
 	Vector<String> full_path_parts = full_file_with_path.rsplit("/", false, 1);
 	Vector<String> full_path_parts = full_file_with_path.rsplit("/", false, 1);
-	const String &full_file_path = full_path_parts.get(0);
-	const String &file_name = full_path_parts.get(1);
-	const String &old_snapshot_name = file_name.split(".").get(0);
-	const String &new_full_file_path = full_file_path.path_join(new_snapshot_name) + ".odb_snapshot";
+	String full_file_path = full_path_parts[0];
+	String file_name = full_path_parts[1];
+	String old_snapshot_name = file_name.split(".")[0];
+	String new_full_file_path = full_file_path.path_join(new_snapshot_name) + ".odb_snapshot";
 
 
 	bool name_taken = false;
 	bool name_taken = false;
 	for (int i = 0; i < snapshot_list->get_root()->get_child_count(); i++) {
 	for (int i = 0; i < snapshot_list->get_root()->get_child_count(); i++) {
@@ -309,14 +313,14 @@ void ObjectDBProfilerPanel::_edit_snapshot_name() {
 	}
 	}
 
 
 	if (name_taken || new_snapshot_name.contains_char(':') || new_snapshot_name.contains_char('\\') || new_snapshot_name.contains_char('/') || new_snapshot_name.begins_with(".") || new_snapshot_name.is_empty()) {
 	if (name_taken || new_snapshot_name.contains_char(':') || new_snapshot_name.contains_char('\\') || new_snapshot_name.contains_char('/') || new_snapshot_name.begins_with(".") || new_snapshot_name.is_empty()) {
-		EditorNode::get_singleton()->show_warning(TTR("Invalid snapshot name."));
+		EditorNode::get_singleton()->show_warning(TTRC("Invalid snapshot name."));
 		snapshot_list->get_selected()->set_text(0, old_snapshot_name);
 		snapshot_list->get_selected()->set_text(0, old_snapshot_name);
 		return;
 		return;
 	}
 	}
 
 
 	Error err = DirAccess::rename_absolute(full_file_with_path, new_full_file_path);
 	Error err = DirAccess::rename_absolute(full_file_with_path, new_full_file_path);
 	if (err != OK) {
 	if (err != OK) {
-		EditorNode::get_singleton()->show_warning(TTR("Snapshot rename failed"));
+		EditorNode::get_singleton()->show_warning(TTRC("Snapshot rename failed"));
 		snapshot_list->get_selected()->set_text(0, old_snapshot_name);
 		snapshot_list->get_selected()->set_text(0, old_snapshot_name);
 	} else {
 	} else {
 		snapshot_list->get_selected()->set_metadata(0, new_full_file_path);
 		snapshot_list->get_selected()->set_metadata(0, new_full_file_path);
@@ -327,11 +331,11 @@ void ObjectDBProfilerPanel::_edit_snapshot_name() {
 }
 }
 
 
 ObjectDBProfilerPanel::ObjectDBProfilerPanel() {
 ObjectDBProfilerPanel::ObjectDBProfilerPanel() {
-	set_name(TTR("ObjectDB Profiler"));
+	set_name(TTRC("ObjectDB Profiler"));
 
 
 	snapshot_cache = LRUCache<String, Ref<GameStateSnapshotRef>>(SNAPSHOT_CACHE_MAX_SIZE);
 	snapshot_cache = LRUCache<String, Ref<GameStateSnapshotRef>>(SNAPSHOT_CACHE_MAX_SIZE);
 
 
-	EditorDebuggerNode::get_singleton()->get_current_debugger()->connect(SNAME("breaked"), callable_mp(this, &ObjectDBProfilerPanel::_on_debug_breaked));
+	EditorDebuggerNode::get_singleton()->get_current_debugger()->connect("breaked", callable_mp(this, &ObjectDBProfilerPanel::_on_debug_breaked));
 
 
 	HSplitContainer *root_container = memnew(HSplitContainer);
 	HSplitContainer *root_container = memnew(HSplitContainer);
 	root_container->set_anchors_preset(Control::LayoutPreset::PRESET_FULL_RECT);
 	root_container->set_anchors_preset(Control::LayoutPreset::PRESET_FULL_RECT);
@@ -343,8 +347,7 @@ ObjectDBProfilerPanel::ObjectDBProfilerPanel() {
 	VBoxContainer *snapshot_column = memnew(VBoxContainer);
 	VBoxContainer *snapshot_column = memnew(VBoxContainer);
 	root_container->add_child(snapshot_column);
 	root_container->add_child(snapshot_column);
 
 
-	// snapshot button
-	take_snapshot = memnew(Button(TTR("Take ObjectDB Snapshot")));
+	take_snapshot = memnew(Button(TTRC("Take ObjectDB Snapshot")));
 	snapshot_column->add_child(take_snapshot);
 	snapshot_column->add_child(take_snapshot);
 	take_snapshot->connect(SceneStringName(pressed), callable_mp(this, &ObjectDBProfilerPanel::_request_object_snapshot));
 	take_snapshot->connect(SceneStringName(pressed), callable_mp(this, &ObjectDBProfilerPanel::_request_object_snapshot));
 
 
@@ -360,13 +363,14 @@ ObjectDBProfilerPanel::ObjectDBProfilerPanel() {
 	snapshot_list->set_column_expand(0, true);
 	snapshot_list->set_column_expand(0, true);
 	snapshot_list->set_column_clip_content(0, true);
 	snapshot_list->set_column_clip_content(0, true);
 	snapshot_list->connect(SceneStringName(item_selected), callable_mp(this, &ObjectDBProfilerPanel::_show_selected_snapshot));
 	snapshot_list->connect(SceneStringName(item_selected), callable_mp(this, &ObjectDBProfilerPanel::_show_selected_snapshot));
+	snapshot_list->connect("nothing_selected", callable_mp(this, &ObjectDBProfilerPanel::_on_snapshot_deselected));
 	snapshot_list->connect("item_edited", callable_mp(this, &ObjectDBProfilerPanel::_edit_snapshot_name));
 	snapshot_list->connect("item_edited", callable_mp(this, &ObjectDBProfilerPanel::_edit_snapshot_name));
 	snapshot_list->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 	snapshot_list->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 	snapshot_list->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 	snapshot_list->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 	snapshot_list->set_anchors_preset(LayoutPreset::PRESET_FULL_RECT);
 	snapshot_list->set_anchors_preset(LayoutPreset::PRESET_FULL_RECT);
 
 
 	snapshot_list->set_allow_rmb_select(true);
 	snapshot_list->set_allow_rmb_select(true);
-	snapshot_list->connect(SNAME("item_mouse_selected"), callable_mp(this, &ObjectDBProfilerPanel::_snapshot_rmb));
+	snapshot_list->connect("item_mouse_selected", callable_mp(this, &ObjectDBProfilerPanel::_snapshot_rmb));
 
 
 	rmb_menu = memnew(PopupMenu);
 	rmb_menu = memnew(PopupMenu);
 	add_child(rmb_menu);
 	add_child(rmb_menu);
@@ -375,12 +379,13 @@ ObjectDBProfilerPanel::ObjectDBProfilerPanel() {
 	HBoxContainer *diff_button_and_label = memnew(HBoxContainer);
 	HBoxContainer *diff_button_and_label = memnew(HBoxContainer);
 	diff_button_and_label->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 	diff_button_and_label->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 	snapshot_column->add_child(diff_button_and_label);
 	snapshot_column->add_child(diff_button_and_label);
-	Label *diff_against = memnew(Label(TTR("Diff Against:")));
+	Label *diff_against = memnew(Label(TTRC("Diff Against:")));
 	diff_button_and_label->add_child(diff_against);
 	diff_button_and_label->add_child(diff_against);
 
 
 	diff_button = memnew(OptionButton);
 	diff_button = memnew(OptionButton);
 	diff_button->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
 	diff_button->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
-	diff_button->connect(SceneStringName(item_selected), callable_mp(this, &ObjectDBProfilerPanel::_apply_diff));
+	diff_button->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
+	diff_button->connect(SceneStringName(item_selected), callable_mp(this, &ObjectDBProfilerPanel::_show_selected_snapshot).unbind(1));
 	diff_button_and_label->add_child(diff_button);
 	diff_button_and_label->add_child(diff_button);
 
 
 	// Tabs of various views right for each snapshot.
 	// Tabs of various views right for each snapshot.
@@ -395,7 +400,6 @@ ObjectDBProfilerPanel::ObjectDBProfilerPanel() {
 	add_view(memnew(SnapshotObjectView));
 	add_view(memnew(SnapshotObjectView));
 	add_view(memnew(SnapshotNodeView));
 	add_view(memnew(SnapshotNodeView));
 	add_view(memnew(SnapshotRefCountedView));
 	add_view(memnew(SnapshotRefCountedView));
-	add_view(memnew(SnapshotJsonView));
 
 
 	set_enabled(false);
 	set_enabled(false);
 
 
@@ -404,10 +408,8 @@ ObjectDBProfilerPanel::ObjectDBProfilerPanel() {
 	if (snapshot_dir.is_valid()) {
 	if (snapshot_dir.is_valid()) {
 		for (const String &file_name : snapshot_dir->get_files()) {
 		for (const String &file_name : snapshot_dir->get_files()) {
 			Vector<String> name_parts = file_name.split(".");
 			Vector<String> name_parts = file_name.split(".");
-			if (name_parts.size() != 2 || name_parts[1] != "odb_snapshot") {
-				ERR_PRINT("ObjectDB Snapshot file did not have .odb_snapshot extension. Skipping: " + file_name);
-				continue;
-			}
+			ERR_CONTINUE_MSG(name_parts.size() != 2 || name_parts[1] != "odb_snapshot", "ObjectDB snapshot file did not have .odb_snapshot extension. Skipping: " + file_name);
+			_add_snapshot_button(name_parts[0], snapshot_dir->get_current_dir().path_join(file_name));
 		}
 		}
 	}
 	}
 }
 }
@@ -415,29 +417,46 @@ ObjectDBProfilerPanel::ObjectDBProfilerPanel() {
 void ObjectDBProfilerPanel::add_view(SnapshotView *p_to_add) {
 void ObjectDBProfilerPanel::add_view(SnapshotView *p_to_add) {
 	views.push_back(p_to_add);
 	views.push_back(p_to_add);
 	view_tabs->add_child(p_to_add);
 	view_tabs->add_child(p_to_add);
+	_update_view_tabs();
+}
+
+void ObjectDBProfilerPanel::_update_view_tabs() {
+	bool has_snapshot = current_snapshot.is_valid();
+	for (int i = 1; i < view_tabs->get_tab_count(); i++) {
+		view_tabs->set_tab_disabled(i, !has_snapshot);
+	}
+
+	if (!has_snapshot) {
+		view_tabs->set_current_tab(0);
+	}
 }
 }
 
 
 void ObjectDBProfilerPanel::_update_diff_items() {
 void ObjectDBProfilerPanel::_update_diff_items() {
 	diff_button->clear();
 	diff_button->clear();
-	diff_button->add_item("none", 0);
-	diff_options[0] = "none";
+	diff_button->add_item(TTRC("None"), 0);
+	diff_button->set_item_metadata(0, String());
+	diff_button->set_item_auto_translate_mode(0, Node::AUTO_TRANSLATE_MODE_ALWAYS);
 
 
 	for (int i = 0; i < snapshot_list->get_root()->get_child_count(); i++) {
 	for (int i = 0; i < snapshot_list->get_root()->get_child_count(); i++) {
-		const String &name = snapshot_list->get_root()->get_child(i)->get_text(0);
+		String name = snapshot_list->get_root()->get_child(i)->get_text(0);
 		diff_button->add_item(name);
 		diff_button->add_item(name);
-		diff_options[i + 1] = name; // 0 = none, so i + 1.
+		diff_button->set_item_metadata(i + 1, name);
 	}
 	}
 }
 }
 
 
 void ObjectDBProfilerPanel::_update_enabled_diff_items() {
 void ObjectDBProfilerPanel::_update_enabled_diff_items() {
-	const String &sn_name = snapshot_list->get_selected()->get_text(0);
-	for (int i = 0; i < diff_button->get_item_count(); i++) {
-		diff_button->set_item_disabled(i, diff_button->get_item_text(i) == sn_name);
+	TreeItem *selected_snapshot = snapshot_list->get_selected();
+	if (selected_snapshot == nullptr) {
+		diff_button->set_disabled(true);
+		return;
 	}
 	}
-}
 
 
-void ObjectDBProfilerPanel::_apply_diff(int p_item_idx) {
-	_show_selected_snapshot();
+	diff_button->set_disabled(false);
+
+	String snapshot_name = selected_snapshot->get_text(0);
+	for (int i = 0; i < diff_button->get_item_count(); i++) {
+		diff_button->set_item_disabled(i, diff_button->get_item_text(i) == snapshot_name);
+	}
 }
 }
 
 
 String ObjectDBProfilerPanel::_to_mb(int p_x) {
 String ObjectDBProfilerPanel::_to_mb(int p_x) {

+ 6 - 6
modules/objectdb_profiler/editor/objectdb_profiler_panel.h

@@ -39,13 +39,13 @@
 class TabContainer;
 class TabContainer;
 class Tree;
 class Tree;
 
 
-const int SNAPSHOT_CACHE_MAX_SIZE = 10;
-
 // UI loaded by the debugger.
 // UI loaded by the debugger.
 class ObjectDBProfilerPanel : public Control {
 class ObjectDBProfilerPanel : public Control {
 	GDCLASS(ObjectDBProfilerPanel, Control);
 	GDCLASS(ObjectDBProfilerPanel, Control);
 
 
 protected:
 protected:
+	static constexpr int SNAPSHOT_CACHE_MAX_SIZE = 10;
+
 	enum OdbProfilerMenuOptions {
 	enum OdbProfilerMenuOptions {
 		ODB_MENU_RENAME,
 		ODB_MENU_RENAME,
 		ODB_MENU_SHOW_IN_FOLDER,
 		ODB_MENU_SHOW_IN_FOLDER,
@@ -66,10 +66,9 @@ protected:
 	TabContainer *view_tabs = nullptr;
 	TabContainer *view_tabs = nullptr;
 	PopupMenu *rmb_menu = nullptr;
 	PopupMenu *rmb_menu = nullptr;
 	OptionButton *diff_button = nullptr;
 	OptionButton *diff_button = nullptr;
-	HashMap<int, String> diff_options;
 	HashMap<int, PartialSnapshot> partial_snapshots;
 	HashMap<int, PartialSnapshot> partial_snapshots;
 
 
-	List<SnapshotView *> views;
+	LocalVector<SnapshotView *> views;
 	Ref<GameStateSnapshotRef> current_snapshot;
 	Ref<GameStateSnapshotRef> current_snapshot;
 	Ref<GameStateSnapshotRef> diff_snapshot;
 	Ref<GameStateSnapshotRef> diff_snapshot;
 	LRUCache<String, Ref<GameStateSnapshotRef>> snapshot_cache;
 	LRUCache<String, Ref<GameStateSnapshotRef>> snapshot_cache;
@@ -78,11 +77,12 @@ protected:
 	void _begin_object_snapshot();
 	void _begin_object_snapshot();
 	void _on_debug_breaked(bool p_reallydid, bool p_can_debug, const String &p_reason, bool p_has_stackdump);
 	void _on_debug_breaked(bool p_reallydid, bool p_can_debug, const String &p_reason, bool p_has_stackdump);
 	void _show_selected_snapshot();
 	void _show_selected_snapshot();
+	void _on_snapshot_deselected();
 	Ref<DirAccess> _get_and_create_snapshot_storage_dir();
 	Ref<DirAccess> _get_and_create_snapshot_storage_dir();
 	TreeItem *_add_snapshot_button(const String &p_snapshot_file_name, const String &p_full_file_path);
 	TreeItem *_add_snapshot_button(const String &p_snapshot_file_name, const String &p_full_file_path);
 	void _snapshot_rmb(const Vector2 &p_pos, MouseButton p_button);
 	void _snapshot_rmb(const Vector2 &p_pos, MouseButton p_button);
 	void _rmb_menu_pressed(int p_tool, bool p_confirm_override);
 	void _rmb_menu_pressed(int p_tool, bool p_confirm_override);
-	void _apply_diff(int p_item_idx);
+	void _update_view_tabs();
 	void _update_diff_items();
 	void _update_diff_items();
 	void _update_enabled_diff_items();
 	void _update_enabled_diff_items();
 	void _edit_snapshot_name();
 	void _edit_snapshot_name();
@@ -94,7 +94,7 @@ public:
 
 
 	void receive_snapshot(int p_request_id);
 	void receive_snapshot(int p_request_id);
 	void show_snapshot(const String &p_snapshot_file_name, const String &p_snapshot_diff_file_name);
 	void show_snapshot(const String &p_snapshot_file_name, const String &p_snapshot_diff_file_name);
-	void clear_snapshot();
+	void clear_snapshot(bool p_update_view_tabs = true);
 	Ref<GameStateSnapshotRef> get_snapshot(const String &p_snapshot_file_name);
 	Ref<GameStateSnapshotRef> get_snapshot(const String &p_snapshot_file_name);
 	void set_enabled(bool p_enabled);
 	void set_enabled(bool p_enabled);
 	void add_view(SnapshotView *p_to_add);
 	void add_view(SnapshotView *p_to_add);

+ 2 - 2
modules/objectdb_profiler/editor/objectdb_profiler_plugin.cpp

@@ -45,8 +45,8 @@ void ObjectDBProfilerDebuggerPlugin::setup_session(int p_session_id) {
 	Ref<EditorDebuggerSession> session = get_session(p_session_id);
 	Ref<EditorDebuggerSession> session = get_session(p_session_id);
 	ERR_FAIL_COND(session.is_null());
 	ERR_FAIL_COND(session.is_null());
 	debugger_panel = memnew(ObjectDBProfilerPanel);
 	debugger_panel = memnew(ObjectDBProfilerPanel);
-	session->connect(SNAME("started"), callable_mp(debugger_panel, &ObjectDBProfilerPanel::set_enabled).bind(true));
-	session->connect(SNAME("stopped"), callable_mp(debugger_panel, &ObjectDBProfilerPanel::set_enabled).bind(false));
+	session->connect("started", callable_mp(debugger_panel, &ObjectDBProfilerPanel::set_enabled).bind(true));
+	session->connect("stopped", callable_mp(debugger_panel, &ObjectDBProfilerPanel::set_enabled).bind(false));
 	session->add_session_tab(debugger_panel);
 	session->add_session_tab(debugger_panel);
 }
 }
 
 

+ 1 - 1
modules/objectdb_profiler/editor/objectdb_profiler_plugin.h

@@ -30,7 +30,7 @@
 
 
 #pragma once
 #pragma once
 
 
-#include "editor/plugins/editor_debugger_plugin.h"
+#include "editor/debugger/editor_debugger_plugin.h"
 #include "editor/plugins/editor_plugin.h"
 #include "editor/plugins/editor_plugin.h"
 
 
 class ObjectDBProfilerPanel;
 class ObjectDBProfilerPanel;

+ 20 - 34
modules/objectdb_profiler/editor/snapshot_data.cpp

@@ -38,8 +38,6 @@
 #include "modules/gdscript/gdscript.h"
 #include "modules/gdscript/gdscript.h"
 #endif
 #endif
 
 
-#include <zlib.h>
-
 SnapshotDataObject::SnapshotDataObject(SceneDebuggerObject &p_obj, GameStateSnapshot *p_snapshot, ResourceCache &resource_cache) :
 SnapshotDataObject::SnapshotDataObject(SceneDebuggerObject &p_obj, GameStateSnapshot *p_snapshot, ResourceCache &resource_cache) :
 		snapshot(p_snapshot) {
 		snapshot(p_snapshot) {
 	remote_object_id = p_obj.id;
 	remote_object_id = p_obj.id;
@@ -48,7 +46,6 @@ SnapshotDataObject::SnapshotDataObject(SceneDebuggerObject &p_obj, GameStateSnap
 	for (const SceneDebuggerObject::SceneDebuggerProperty &prop : p_obj.properties) {
 	for (const SceneDebuggerObject::SceneDebuggerProperty &prop : p_obj.properties) {
 		PropertyInfo pinfo = prop.first;
 		PropertyInfo pinfo = prop.first;
 		Variant pvalue = prop.second;
 		Variant pvalue = prop.second;
-		// pinfo.name = pinfo.name.trim_prefix("Node/").trim_prefix("Members/");
 
 
 		if (pinfo.type == Variant::OBJECT && pvalue.is_string()) {
 		if (pinfo.type == Variant::OBJECT && pvalue.is_string()) {
 			String path = pvalue;
 			String path = pvalue;
@@ -56,7 +53,7 @@ SnapshotDataObject::SnapshotDataObject(SceneDebuggerObject &p_obj, GameStateSnap
 			// To get a reference to it, first we load the parent resource (the .tscn, for example), then,
 			// To get a reference to it, first we load the parent resource (the .tscn, for example), then,
 			// we load the child resource. The parent resource (dependency) should not be destroyed before the child
 			// we load the child resource. The parent resource (dependency) should not be destroyed before the child
 			// resource (pvalue) is loaded.
 			// resource (pvalue) is loaded.
-			if (path.contains("::")) {
+			if (path.is_resource_file()) {
 				// Built-in resource.
 				// Built-in resource.
 				String base_path = path.get_slice("::", 0);
 				String base_path = path.get_slice("::", 0);
 				if (!resource_cache.cache.has(base_path)) {
 				if (!resource_cache.cache.has(base_path)) {
@@ -160,27 +157,22 @@ String SnapshotDataObject::get_name() {
 	String found_type_name = type_name;
 	String found_type_name = type_name;
 
 
 	// Ideally, we will name it after the script attached to it.
 	// Ideally, we will name it after the script attached to it.
-	if (!get_script().is_null()) {
-		Object *maybe_script_obj = get_script().get_validated_object();
-
-		if (maybe_script_obj->is_class(Script::get_class_static())) {
-			Ref<Script> script_obj = Ref<Script>((Script *)maybe_script_obj);
-
-			String full_name;
-			while (script_obj.is_valid()) {
-				String global_name = _get_script_name(script_obj);
-				if (global_name != "") {
-					if (full_name != "") {
-						full_name = global_name + "/" + full_name;
-					} else {
-						full_name = global_name;
-					}
+	Ref<Script> maybe_script = get_script();
+	if (maybe_script.is_valid()) {
+		String full_name;
+		while (maybe_script.is_valid()) {
+			String global_name = _get_script_name(maybe_script);
+			if (global_name != "") {
+				if (full_name != "") {
+					full_name = global_name + "/" + full_name;
+				} else {
+					full_name = global_name;
 				}
 				}
-				script_obj = script_obj->get_base_script().ptr();
 			}
 			}
-
-			found_type_name = type_name + "/" + full_name;
+			maybe_script = maybe_script->get_base_script().ptr();
 		}
 		}
+
+		found_type_name = type_name + "/" + full_name;
 	}
 	}
 
 
 	return found_type_name + "_" + uitos(remote_object_id);
 	return found_type_name + "_" + uitos(remote_object_id);
@@ -258,7 +250,7 @@ void GameStateSnapshot::_get_rc_cycles(
 		SnapshotDataObject *p_obj,
 		SnapshotDataObject *p_obj,
 		SnapshotDataObject *p_source_obj,
 		SnapshotDataObject *p_source_obj,
 		HashSet<SnapshotDataObject *> p_traversed_objs,
 		HashSet<SnapshotDataObject *> p_traversed_objs,
-		List<String> &r_ret_val,
+		LocalVector<String> &r_ret_val,
 		const String &p_current_path) {
 		const String &p_current_path) {
 	// We're at the end of this branch and it was a cycle.
 	// We're at the end of this branch and it was a cycle.
 	if (p_obj == p_source_obj && p_current_path != "") {
 	if (p_obj == p_source_obj && p_current_path != "") {
@@ -314,7 +306,7 @@ void GameStateSnapshot::recompute_references() {
 			continue;
 			continue;
 		}
 		}
 		HashSet<SnapshotDataObject *> traversed_objs;
 		HashSet<SnapshotDataObject *> traversed_objs;
-		List<String> cycles;
+		LocalVector<String> cycles;
 
 
 		_get_rc_cycles(obj.value, obj.value, traversed_objs, cycles, "");
 		_get_rc_cycles(obj.value, obj.value, traversed_objs, cycles, "");
 		Array cycles_array;
 		Array cycles_array;
@@ -340,22 +332,16 @@ Ref<GameStateSnapshotRef> GameStateSnapshot::create_ref(const String &p_snapshot
 	CoreBind::Marshalls *m = CoreBind::Marshalls::get_singleton();
 	CoreBind::Marshalls *m = CoreBind::Marshalls::get_singleton();
 	Array snapshot_data = m->base64_to_variant(m->raw_to_base64(snapshot_buffer_decompressed));
 	Array snapshot_data = m->base64_to_variant(m->raw_to_base64(snapshot_buffer_decompressed));
 	ERR_FAIL_COND_V_MSG(snapshot_data.is_empty(), nullptr, "ObjectDB Snapshot could not be parsed. Variant array is empty.");
 	ERR_FAIL_COND_V_MSG(snapshot_data.is_empty(), nullptr, "ObjectDB Snapshot could not be parsed. Variant array is empty.");
-	const Variant &first_item = snapshot_data.get(0);
-	if (first_item.get_type() != Variant::DICTIONARY) {
-		ERR_PRINT("ObjectDB Snapshot could not be parsed. First item is not a Dictionary.");
-		return nullptr;
-	}
+	const Variant &first_item = snapshot_data[0];
+	ERR_FAIL_COND_V_MSG(first_item.get_type() != Variant::DICTIONARY, nullptr, "ObjectDB Snapshot could not be parsed. First item is not a Dictionary.");
 	snapshot->snapshot_context = first_item;
 	snapshot->snapshot_context = first_item;
 
 
 	SnapshotDataObject::ResourceCache resource_cache;
 	SnapshotDataObject::ResourceCache resource_cache;
 	for (int i = 1; i < snapshot_data.size(); i += 4) {
 	for (int i = 1; i < snapshot_data.size(); i += 4) {
 		SceneDebuggerObject obj;
 		SceneDebuggerObject obj;
 		obj.deserialize(uint64_t(snapshot_data[i + 0]), snapshot_data[i + 1], snapshot_data[i + 2]);
 		obj.deserialize(uint64_t(snapshot_data[i + 0]), snapshot_data[i + 1], snapshot_data[i + 2]);
+		ERR_FAIL_COND_V_MSG(snapshot_data[i + 3].get_type() != Variant::DICTIONARY, nullptr, "ObjectDB Snapshot could not be parsed. Extra debug data is not a Dictionary.");
 
 
-		if (snapshot_data[i + 3].get_type() != Variant::DICTIONARY) {
-			ERR_PRINT("ObjectDB Snapshot could not be parsed. Extra debug data is not a Dictionary.");
-			return nullptr;
-		}
 		if (obj.id.is_null()) {
 		if (obj.id.is_null()) {
 			continue;
 			continue;
 		}
 		}
@@ -371,7 +357,7 @@ Ref<GameStateSnapshotRef> GameStateSnapshot::create_ref(const String &p_snapshot
 
 
 GameStateSnapshot::~GameStateSnapshot() {
 GameStateSnapshot::~GameStateSnapshot() {
 	for (const KeyValue<ObjectID, SnapshotDataObject *> &item : objects) {
 	for (const KeyValue<ObjectID, SnapshotDataObject *> &item : objects) {
-		memfree(item.value);
+		memdelete(item.value);
 	}
 	}
 }
 }
 
 

+ 4 - 4
modules/objectdb_profiler/editor/snapshot_data.h

@@ -50,9 +50,9 @@ public:
 	HashSet<ObjectID> get_unique_outbound_refernces();
 	HashSet<ObjectID> get_unique_outbound_refernces();
 	HashSet<ObjectID> get_unique_inbound_references();
 	HashSet<ObjectID> get_unique_inbound_references();
 
 
-	uint64_t remote_object_id;
+	uint64_t remote_object_id = 0;
 	String type_name;
 	String type_name;
-	List<PropertyInfo> prop_list;
+	LocalVector<PropertyInfo> prop_list;
 	HashMap<StringName, Variant> prop_values;
 	HashMap<StringName, Variant> prop_values;
 	bool _get(const StringName &p_name, Variant &r_ret) const;
 	bool _get(const StringName &p_name, Variant &r_ret) const;
 	void _get_property_list(List<PropertyInfo> *p_list) const;
 	void _get_property_list(List<PropertyInfo> *p_list) const;
@@ -72,7 +72,7 @@ public:
 	bool is_class(const String &p_base_class);
 	bool is_class(const String &p_base_class);
 
 
 protected:
 protected:
-	// Snapshots are inheritly read-only. Can't edit the past.
+	// Snapshots are inherently read-only. Can't edit the past.
 	bool _is_read_only() { return true; }
 	bool _is_read_only() { return true; }
 	static void _bind_methods();
 	static void _bind_methods();
 };
 };
@@ -81,7 +81,7 @@ class GameStateSnapshot : public Object {
 	GDCLASS(GameStateSnapshot, Object);
 	GDCLASS(GameStateSnapshot, Object);
 
 
 	void _get_outbound_references(Variant &p_var, HashMap<String, ObjectID> &r_ret_val, const String &p_current_path = "");
 	void _get_outbound_references(Variant &p_var, HashMap<String, ObjectID> &r_ret_val, const String &p_current_path = "");
-	void _get_rc_cycles(SnapshotDataObject *p_obj, SnapshotDataObject *p_source_obj, HashSet<SnapshotDataObject *> p_traversed_objs, List<String> &r_ret_val, const String &p_current_path = "");
+	void _get_rc_cycles(SnapshotDataObject *p_obj, SnapshotDataObject *p_source_obj, HashSet<SnapshotDataObject *> p_traversed_objs, LocalVector<String> &r_ret_val, const String &p_current_path = "");
 
 
 public:
 public:
 	String name;
 	String name;

+ 8 - 19
modules/objectdb_profiler/register_types.cpp

@@ -37,29 +37,18 @@
 #endif // TOOLS_ENABLED
 #endif // TOOLS_ENABLED
 
 
 void initialize_objectdb_profiler_module(ModuleInitializationLevel p_level) {
 void initialize_objectdb_profiler_module(ModuleInitializationLevel p_level) {
-	switch (p_level) {
-		case MODULE_INITIALIZATION_LEVEL_SCENE: {
-			SnapshotCollector::initialize();
-		} break;
-
+	if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
+		SnapshotCollector::initialize();
+	}
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
-		case MODULE_INITIALIZATION_LEVEL_EDITOR: {
-			EditorPlugins::add_by_type<ObjectDBProfilerPlugin>();
-		} break;
-#endif // TOOLS_ENABLED
-
-		default:
-			break;
+	else if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
+		EditorPlugins::add_by_type<ObjectDBProfilerPlugin>();
 	}
 	}
+#endif // TOOLS_ENABLED
 }
 }
 
 
 void uninitialize_objectdb_profiler_module(ModuleInitializationLevel p_level) {
 void uninitialize_objectdb_profiler_module(ModuleInitializationLevel p_level) {
-	switch (p_level) {
-		case MODULE_INITIALIZATION_LEVEL_SCENE: {
-			SnapshotCollector::deinitialize();
-		} break;
-
-		default:
-			break;
+	if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
+		SnapshotCollector::deinitialize();
 	}
 	}
 }
 }

+ 24 - 33
modules/objectdb_profiler/snapshot_collector.cpp

@@ -37,8 +37,6 @@
 #include "scene/main/node.h"
 #include "scene/main/node.h"
 #include "scene/main/window.h"
 #include "scene/main/window.h"
 
 
-HashMap<int, Vector<uint8_t>> SnapshotCollector::pending_snapshots;
-
 void SnapshotCollector::initialize() {
 void SnapshotCollector::initialize() {
 	pending_snapshots.clear();
 	pending_snapshots.clear();
 	EngineDebugger::register_message_capture("snapshot", EngineDebugger::Capture(nullptr, SnapshotCollector::parse_message));
 	EngineDebugger::register_message_capture("snapshot", EngineDebugger::Capture(nullptr, SnapshotCollector::parse_message));
@@ -56,36 +54,34 @@ void SnapshotCollector::snapshot_objects(Array *p_arr, Dictionary &p_snapshot_co
 	// Gather all ObjectIDs first. The ObjectDB will be locked in debug_objects, so we can't serialize until it exits.
 	// Gather all ObjectIDs first. The ObjectDB will be locked in debug_objects, so we can't serialize until it exits.
 
 
 	// In rare cases, the object may be deleted as the snapshot is taken. So, we store the object's class name to give users a clue about what went wrong.
 	// In rare cases, the object may be deleted as the snapshot is taken. So, we store the object's class name to give users a clue about what went wrong.
-	List<Pair<ObjectID, String>> debugger_object_ids;
-	ObjectDB::debug_objects([](Object *p_obj, void *p_user_data) {
-		List<Pair<ObjectID, String>> *debugger_object_ids_ptr = (List<Pair<ObjectID, String>> *)p_user_data;
-		debugger_object_ids_ptr->push_back(Pair<ObjectID, String>(p_obj->get_instance_id(), p_obj->get_class_name()));
-	},
+	LocalVector<Pair<ObjectID, StringName>> debugger_object_ids;
+	debugger_object_ids.reserve(ObjectDB::get_object_count());
+
+	ObjectDB::debug_objects(
+			[](Object *p_obj, void *p_user_data) {
+				LocalVector<Pair<ObjectID, StringName>> *debugger_object_ids_ptr = (LocalVector<Pair<ObjectID, StringName>> *)p_user_data;
+				debugger_object_ids_ptr->push_back(Pair<ObjectID, StringName>(p_obj->get_instance_id(), p_obj->get_class_name()));
+			},
 			(void *)&debugger_object_ids);
 			(void *)&debugger_object_ids);
 
 
 	// Get SnapshotDataTransportObject from ObjectID list now that DB is unlocked.
 	// Get SnapshotDataTransportObject from ObjectID list now that DB is unlocked.
-	List<SnapshotDataTransportObject> debugger_objects;
-	for (Pair<ObjectID, String> ids : debugger_object_ids) {
+	LocalVector<SnapshotDataTransportObject> debugger_objects;
+	debugger_objects.reserve(debugger_object_ids.size());
+	for (Pair<ObjectID, StringName> ids : debugger_object_ids) {
 		ObjectID oid = ids.first;
 		ObjectID oid = ids.first;
 		Object *obj = ObjectDB::get_instance(oid);
 		Object *obj = ObjectDB::get_instance(oid);
-
-		if (obj == nullptr) {
-			print_error("An object was deleted while the ObjectDB was being snapshotted. \
-				The debugger is automatically paused when snapshots are taken, so this should not happen. \
-				The missing object's ID was " +
-					String::num_uint64(oid) + ". \
-				 It's class was " +
-					ids.second + ". Consider reporting this.");
+		if (unlikely(obj == nullptr)) {
+			print_verbose(vformat("Object of class '%s' with ID %ud was found to be deleted after ObjectDB was snapshotted.", ids.second, (uint64_t)oid));
 			continue;
 			continue;
 		}
 		}
 
 
-		if (obj->get_class_name() == SNAME("EditorInterface")) {
-			// The EditorInterface + EditorNode is _kind of_ constructored in a debug game, but many properties rae null
+		if (ids.second == SNAME("EditorInterface")) {
+			// The EditorInterface + EditorNode is _kind of_ constructed in a debug game, but many properties are null
 			// We can prevent it from being constructed, but that would break other projects so better to just skip it.
 			// We can prevent it from being constructed, but that would break other projects so better to just skip it.
 			continue;
 			continue;
 		}
 		}
 
 
-		// This is the same way objects in the remote scene tree are seialized,
+		// This is the same way objects in the remote scene tree are serialized,
 		// but here we add a few extra properties via the extra_debug_data dictionary.
 		// but here we add a few extra properties via the extra_debug_data dictionary.
 		SnapshotDataTransportObject debug_data(obj);
 		SnapshotDataTransportObject debug_data(obj);
 
 
@@ -115,7 +111,6 @@ void SnapshotCollector::snapshot_objects(Array *p_arr, Dictionary &p_snapshot_co
 	}
 	}
 
 
 	// Add a header to the snapshot with general data about the state of the game, not tied to any particular object.
 	// Add a header to the snapshot with general data about the state of the game, not tied to any particular object.
-	p_snapshot_context["mem_available"] = Memory::get_mem_available();
 	p_snapshot_context["mem_usage"] = Memory::get_mem_usage();
 	p_snapshot_context["mem_usage"] = Memory::get_mem_usage();
 	p_snapshot_context["mem_max_usage"] = Memory::get_mem_max_usage();
 	p_snapshot_context["mem_max_usage"] = Memory::get_mem_max_usage();
 	p_snapshot_context["timestamp"] = Time::get_singleton()->get_unix_time_from_system();
 	p_snapshot_context["timestamp"] = Time::get_singleton()->get_unix_time_from_system();
@@ -132,11 +127,11 @@ void SnapshotCollector::snapshot_objects(Array *p_arr, Dictionary &p_snapshot_co
 Error SnapshotCollector::parse_message(void *p_user, const String &p_msg, const Array &p_args, bool &r_captured) {
 Error SnapshotCollector::parse_message(void *p_user, const String &p_msg, const Array &p_args, bool &r_captured) {
 	r_captured = true;
 	r_captured = true;
 	if (p_msg == "request_prepare_snapshot") {
 	if (p_msg == "request_prepare_snapshot") {
-		int request_id = (int)p_args.get(0);
+		int request_id = p_args[0];
 		Dictionary snapshot_context;
 		Dictionary snapshot_context;
-		snapshot_context["editor_version"] = (String)p_args.get(1);
+		snapshot_context["editor_version"] = (String)p_args[1];
 		Array objects;
 		Array objects;
-		SnapshotCollector::snapshot_objects(&objects, snapshot_context);
+		snapshot_objects(&objects, snapshot_context);
 		// Debugger networking has a limit on both how many objects can be queued to send and how
 		// Debugger networking has a limit on both how many objects can be queued to send and how
 		// many bytes can be queued to send. Serializing to a string means we never hit the object
 		// many bytes can be queued to send. Serializing to a string means we never hit the object
 		// limit, and only have to deal with the byte limit.
 		// limit, and only have to deal with the byte limit.
@@ -150,19 +145,15 @@ Error SnapshotCollector::parse_message(void *p_user, const String &p_msg, const
 		pending_snapshots[request_id] = objs_buffer_compressed;
 		pending_snapshots[request_id] = objs_buffer_compressed;
 
 
 		// Tell the editor how long the snapshot is.
 		// Tell the editor how long the snapshot is.
-		Array resp;
-		resp.push_back(request_id);
-		resp.push_back(pending_snapshots[request_id].size());
+		Array resp = { request_id, pending_snapshots[request_id].size() };
 		EngineDebugger::get_singleton()->send_message("snapshot:snapshot_prepared", resp);
 		EngineDebugger::get_singleton()->send_message("snapshot:snapshot_prepared", resp);
 
 
 	} else if (p_msg == "request_snapshot_chunk") {
 	} else if (p_msg == "request_snapshot_chunk") {
-		int request_id = (int)p_args.get(0);
-		int begin = (int)p_args.get(1);
-		int end = (int)p_args.get(2);
+		int request_id = p_args[0];
+		int begin = p_args[1];
+		int end = p_args[2];
 
 
-		Array resp;
-		resp.push_back(request_id);
-		resp.push_back(pending_snapshots[request_id].slice(begin, end));
+		Array resp = { request_id, pending_snapshots[request_id].slice(begin, end) };
 		EngineDebugger::get_singleton()->send_message("snapshot:snapshot_chunk", resp);
 		EngineDebugger::get_singleton()->send_message("snapshot:snapshot_chunk", resp);
 
 
 		// If we sent the last part of the string, delete it locally.
 		// If we sent the last part of the string, delete it locally.

+ 2 - 1
modules/objectdb_profiler/snapshot_collector.h

@@ -42,8 +42,9 @@ struct SnapshotDataTransportObject : public SceneDebuggerObject {
 };
 };
 
 
 class SnapshotCollector {
 class SnapshotCollector {
+	inline static HashMap<int, Vector<uint8_t>> pending_snapshots;
+
 public:
 public:
-	static HashMap<int, Vector<uint8_t>> pending_snapshots;
 	static void snapshot_objects(Array *p_arr, Dictionary &p_snapshot_context);
 	static void snapshot_objects(Array *p_arr, Dictionary &p_snapshot_context);
 	static Error parse_message(void *p_user, const String &p_msg, const Array &p_args, bool &r_captured);
 	static Error parse_message(void *p_user, const String &p_msg, const Array &p_args, bool &r_captured);
 	static void initialize();
 	static void initialize();

+ 0 - 5
scene/gui/tree.cpp

@@ -5787,11 +5787,6 @@ String Tree::get_column_title(int p_column) const {
 
 
 void Tree::set_column_title_tooltip_text(int p_column, const String &p_tooltip) {
 void Tree::set_column_title_tooltip_text(int p_column, const String &p_tooltip) {
 	ERR_FAIL_INDEX(p_column, columns.size());
 	ERR_FAIL_INDEX(p_column, columns.size());
-
-	if (columns.write[p_column].title_tooltip == p_tooltip) {
-		return;
-	}
-
 	columns.write[p_column].title_tooltip = p_tooltip;
 	columns.write[p_column].title_tooltip = p_tooltip;
 }
 }