Repository: godotengine/godot (language: cpp)

Issue:
Remote scene tree loses reference to resource in inspector at runtime
### Tested versions

- Reproducible in: 4.5dev1

### System information

Godot v4.5.dev1 - Windows 10 (build 19045) - Multi-window, 1 monitor - Vulkan (Forward+) - dedicated NVIDIA GeForce GTX 1060 (NVIDIA; 32.0.15.6603) - Intel(R) Core(TM) i5-6300HQ CPU @ 2.30GHz (4 threads)

### Issue description

Using `lose reference` may not be accurate, but the resoureces are indeed invisible.

Demonstration:

https://github.com/user-attachments/assets/6b1bbe8b-fd74-47c0-80b5-710f3aeb174e

### Steps to reproduce

Just run the mrp, then switch to remote tree and you will find it loses references to resources. (e.g. CollisionShape2D, material, script)

### Minimal reproduction project (MRP)

[remote_tree_2.zip](https://github.com/user-attachments/files/19434062/remote_tree_2.zip)


Discussion / hints:
Please provide an MRP to make this easier to test and fix:
- A small Godot project which reproduces the issue, with no unnecessary files included. Be sure to not include the `.godot` folder in the archive (but keep `project.godot`).
- Having an MRP is very important for contributors to be able to reproduce the bug in the same way that you are experiencing it. When testing a potential fix for the issue, contributors will use the MRP to validate that the fix is working as intended.
- Drag and drop a ZIP archive to upload it (max 10 MB). **Do not select another field until the project is done uploading.**
- **Note for C# users:** If your issue is *not* C#-specific, please upload a minimal reproduction project written in GDScript. This will make it easier for contributors to reproduce the issue locally as not everyone has a .NET setup available. 
> Please provide an MRP to make this easier to test and fix:
> 
> * A small Godot project which reproduces the issue, with no unnecessary files included. Be sure to not include the `.godot` folder in the archive (but keep `project.godot`).
> * Having an MRP is very important for contributors to be able to reproduce the bug in the same way that you are experiencing it. When testing a potential fix for the issue, contributors will use the MRP to validate that the fix is working as intended.
> * Drag and drop a ZIP archive to upload it (max 10 MB). **Do not select another field until the project is done uploading.**
> * **Note for C# users:** If your issue is _not_ C#-specific, please upload a minimal reproduction project written in GDScript. This will make it easier for contributors to reproduce the issue locally as not everyone has a .NET setup available.

Added. Since it's easily to reproduce that i skipped adding mrp out of laziness.
The zip file appears to be empty, or corrupted
> The zip file appears to be empty, or corrupted

Reuploaded and should be right now.
Can confirm and this is a regression not present in 4.4, bisecting
Bisected to:
* https://github.com/godotengine/godot/pull/99680

So seem to be the same underlying issue as:
* https://github.com/godotengine/godot/issues/104445

Probably the same bug but keeping separate to ensure all affected areas are fixed

CC @YeldhamDev 

Fix patch:
diff --git a/editor/debugger/editor_debugger_inspector.cpp b/editor/debugger/editor_debugger_inspector.cpp
index 7e9e963bebc2..121378a75608 100644
--- a/editor/debugger/editor_debugger_inspector.cpp
+++ b/editor/debugger/editor_debugger_inspector.cpp
@@ -271,7 +271,7 @@ EditorDebuggerRemoteObjects *EditorDebuggerInspector::set_objects(const Array &p
 	remote_objects->prop_list.clear();
 	int new_props_added = 0;
 	HashSet<String> changed;
-	for (const KeyValue<String, UsageData> &KV : usage) {
+	for (KeyValue<String, UsageData> &KV : usage) {
 		const PropertyInfo &pinfo = KV.value.prop.first;
 		Variant var = KV.value.values[remote_objects->remote_object_ids[0]];
 
@@ -287,6 +287,7 @@ EditorDebuggerRemoteObjects *EditorDebuggerInspector::set_objects(const Array &p
 					}
 				}
 				var = ResourceLoader::load(path);
+				KV.value.values[remote_objects->remote_object_ids[0]] = var;
 
 				if (pinfo.hint_string == "Script") {
 					if (remote_objects->get_script() != var) {
diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp
index d63a89216968..04cf64265f9d 100644
--- a/editor/debugger/editor_debugger_node.cpp
+++ b/editor/debugger/editor_debugger_node.cpp
@@ -116,6 +116,7 @@ ScriptEditorDebugger *EditorDebuggerNode::_add_debugger() {
 	node->connect("remote_tree_updated", callable_mp(this, &EditorDebuggerNode::_remote_tree_updated).bind(id));
 	node->connect("remote_objects_updated", callable_mp(this, &EditorDebuggerNode::_remote_objects_updated).bind(id));
 	node->connect("remote_object_property_updated", callable_mp(this, &EditorDebuggerNode::_remote_object_property_updated).bind(id));
+	node->connect("remote_objects_requested", callable_mp(this, &EditorDebuggerNode::_remote_objects_requested).bind(id));
 	node->connect("set_breakpoint", callable_mp(this, &EditorDebuggerNode::_breakpoint_set_in_tree).bind(id));
 	node->connect("clear_breakpoints", callable_mp(this, &EditorDebuggerNode::_breakpoints_cleared_in_tree).bind(id));
 	node->connect("errors_cleared", callable_mp(this, &EditorDebuggerNode::_update_errors));
@@ -679,8 +680,6 @@ void EditorDebuggerNode::request_remote_tree() {
 }
 
 void EditorDebuggerNode::set_remote_selection(const TypedArray<int64_t> &p_ids) {
-	remote_scene_tree->select_nodes(p_ids);
-
 	stop_waiting_inspection();
 	get_current_debugger()->request_remote_objects(p_ids);
 }
diff --git a/editor/debugger/editor_expression_evaluator.cpp b/editor/debugger/editor_expression_evaluator.cpp
index 369361cdbac9..20bfbdd1caa8 100644
--- a/editor/debugger/editor_expression_evaluator.cpp
+++ b/editor/debugger/editor_expression_evaluator.cpp
@@ -74,7 +74,9 @@ void EditorExpressionEvaluator::_clear() {
 }
 
 void EditorExpressionEvaluator::_remote_object_selected(ObjectID p_id) {
-	editor_debugger->emit_signal(SNAME("remote_object_requested"), p_id);
+	Array arr;
+	arr.append(p_id);
+	editor_debugger->emit_signal(SNAME("remote_objects_requested"), arr);
 }
 
 void EditorExpressionEvaluator::_on_expression_input_changed(const String &p_expression) {
diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp
index 1db15bcdced0..5a10ada61496 100644
--- a/editor/debugger/script_editor_debugger.cpp
+++ b/editor/debugger/script_editor_debugger.cpp
@@ -300,7 +300,9 @@ void ScriptEditorDebugger::clear_inspector(bool p_send_msg) {
 }
 
 void ScriptEditorDebugger::_remote_object_selected(ObjectID p_id) {
-	emit_signal(SNAME("remote_object_requested"), p_id);
+	Array arr;
+	arr.append(p_id);
+	emit_signal(SNAME("remote_objects_requested"), arr);
 }
 
 void ScriptEditorDebugger::_remote_objects_edited(const String &p_prop, const TypedDictionary<uint64_t, Variant> &p_values, const String &p_field) {
@@ -439,16 +441,10 @@ void ScriptEditorDebugger::_msg_scene_scene_tree(uint64_t p_thread_id, const Arr
 
 void ScriptEditorDebugger::_msg_scene_inspect_objects(uint64_t p_thread_id, const Array &p_data) {
 	ERR_FAIL_COND(p_data.is_empty());
+	EditorDebuggerRemoteObjects *objs = inspector->set_objects(p_data);
+	if (objs && EditorDebuggerNode::get_singleton()->match_remote_selection(objs->remote_object_ids)) {
+		EditorDebuggerNode::get_singleton()->stop_waiting_inspection();
 
-	TypedArray<uint64_t> ids;
-	for (const Array arr : p_data) {
-		ERR_FAIL_COND(arr.is_empty());
-		ERR_FAIL_COND(arr[0].get_type() != Variant::INT);
-		ids.append(arr[0]);
-	}
-
-	if (EditorDebuggerNode::get_singleton()->match_remote_selection(ids)) {
-		EditorDebuggerRemoteObjects *objs = inspector->set_objects(p_data);
 		emit_signal(SNAME("remote_objects_updated"), objs);
 	}
 }
@@ -881,7 +877,7 @@ void ScriptEditorDebugger::_msg_request_quit(uint64_t p_thread_id, const Array &
 	_stop_and_notify();
 }
 
-void ScriptEditorDebugger::_msg_remote_nodes_clicked(uint64_t p_thread_id, const Array &p_data) {
+void ScriptEditorDebugger::_msg_remote_objects_selected(uint64_t p_thread_id, const Array &p_data) {
 	ERR_FAIL_COND(p_data.is_empty());
 	EditorDebuggerRemoteObjects *objs = inspector->set_objects(p_data);
 	if (objs) {
@@ -892,7 +888,7 @@ void ScriptEditorDebugger::_msg_remote_nodes_clicked(uint64_t p_thread_id, const
 	}
 }
 
-void ScriptEditorDebugger::_msg_remote_nothing_clicked(uint64_t p_thread_id, const Array &p_data) {
+void ScriptEditorDebugger::_msg_remote_nothing_selected(uint64_t p_thread_id, const Array &p_data) {
 	EditorDebuggerNode::get_singleton()->stop_waiting_inspection();
 
 	emit_signal(SNAME("remote_tree_clear_selection_requested"));
@@ -973,8 +969,8 @@ void ScriptEditorDebugger::_init_parse_message_handlers() {
 	parse_message_handlers["servers:profile_frame"] = &ScriptEditorDebugger::_msg_servers_profile_frame;
 	parse_message_handlers["servers:profile_total"] = &ScriptEditorDebugger::_msg_servers_profile_total;
 	parse_message_handlers["request_quit"] = &ScriptEditorDebugger::_msg_request_quit;
-	parse_message_handlers["remote_nodes_clicked"] = &ScriptEditorDebugger::_msg_remote_nodes_clicked;
-	parse_message_handlers["remote_nothing_clicked"] = &ScriptEditorDebugger::_msg_remote_nothing_clicked;
+	parse_message_handlers["remote_objects_selected"] = &ScriptEditorDebugger::_msg_remote_objects_selected;
+	parse_message_handlers["remote_nothing_selected"] = &ScriptEditorDebugger::_msg_remote_nothing_selected;
 	parse_message_handlers["remote_selection_invalidated"] = &ScriptEditorDebugger::_msg_remote_selection_invalidated;
 	parse_message_handlers["show_selection_limit_warning"] = &ScriptEditorDebugger::_msg_show_selection_limit_warning;
 	parse_message_handlers["performance:profile_names"] = &ScriptEditorDebugger::_msg_performance_profile_names;
@@ -1956,6 +1952,7 @@ void ScriptEditorDebugger::_bind_methods() {
 	ADD_SIGNAL(MethodInfo("set_execution", PropertyInfo("script"), PropertyInfo(Variant::INT, "line")));
 	ADD_SIGNAL(MethodInfo("clear_execution", PropertyInfo("script")));
 	ADD_SIGNAL(MethodInfo("breaked", PropertyInfo(Variant::BOOL, "reallydid"), PropertyInfo(Variant::BOOL, "can_debug"), PropertyInfo(Variant::STRING, "reason"), PropertyInfo(Variant::BOOL, "has_stackdump")));
+	ADD_SIGNAL(MethodInfo("remote_objects_requested", PropertyInfo(Variant::ARRAY, "ids")));
 	ADD_SIGNAL(MethodInfo("remote_objects_updated", PropertyInfo(Variant::OBJECT, "remote_objects")));
 	ADD_SIGNAL(MethodInfo("remote_object_property_updated", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::STRING, "property")));
 	ADD_SIGNAL(MethodInfo("remote_window_title_changed", PropertyInfo(Variant::STRING, "title")));
diff --git a/editor/debugger/script_editor_debugger.h b/editor/debugger/script_editor_debugger.h
index 852deaf00a82..ff736cd3ba2a 100644
--- a/editor/debugger/script_editor_debugger.h
+++ b/editor/debugger/script_editor_debugger.h
@@ -217,8 +217,8 @@ class ScriptEditorDebugger : public MarginContainer {
 	void _msg_servers_profile_frame(uint64_t p_thread_id, const Array &p_data);
 	void _msg_servers_profile_total(uint64_t p_thread_id, const Array &p_data);
 	void _msg_request_quit(uint64_t p_thread_id, const Array &p_data);
-	void _msg_remote_nodes_clicked(uint64_t p_thread_id, const Array &p_data);
-	void _msg_remote_nothing_clicked(uint64_t p_thread_id, const Array &p_data);
+	void _msg_remote_objects_selected(uint64_t p_thread_id, const Array &p_data);
+	void _msg_remote_nothing_selected(uint64_t p_thread_id, const Array &p_data);
 	void _msg_remote_selection_invalidated(uint64_t p_thread_id, const Array &p_data);
 	void _msg_show_selection_limit_warning(uint64_t p_thread_id, const Array &p_data);
 	void _msg_performance_profile_names(uint64_t p_thread_id, const Array &p_data);
diff --git a/scene/debugger/scene_debugger.cpp b/scene/debugger/scene_debugger.cpp
index 3234239d826b..5afcb8fd819e 100644
--- a/scene/debugger/scene_debugger.cpp
+++ b/scene/debugger/scene_debugger.cpp
@@ -407,9 +407,9 @@ void SceneDebugger::_send_object_ids(const Vector<ObjectID> &p_ids, bool p_updat
 		arr.append(invalid_selection);
 		EngineDebugger::get_singleton()->send_message("remote_selection_invalidated", arr);
 
-		EngineDebugger::get_singleton()->send_message(objs.is_empty() ? "remote_nothing_clicked" : "remote_nodes_clicked", objs);
+		EngineDebugger::get_singleton()->send_message(objs.is_empty() ? "remote_nothing_selected" : "remote_objects_selected", objs);
 	} else {
-		EngineDebugger::get_singleton()->send_message("scene:inspect_objects", objs);
+		EngineDebugger::get_singleton()->send_message(p_update_selection ? "remote_objects_selected" : "scene:inspect_objects", objs);
 	}
 }
 
@@ -1652,7 +1652,7 @@ void RuntimeNodeSelect::_physics_frame() {
 #else
 				if (!selected_ci_nodes.is_empty() || !selected_3d_nodes.is_empty()) {
 #endif // _3D_DISABLED
-					EngineDebugger::get_singleton()->send_message("remote_nothing_clicked", Array());
+					EngineDebugger::get_singleton()->send_message("remote_nothing_selected", Array());
 					_clear_selection();
 				}
 
@@ -1714,7 +1714,7 @@ void RuntimeNodeSelect::_send_ids(const Vector<Node *> &p_picked_nodes, bool p_i
 			message.append(arr);
 		}
 
-		EngineDebugger::get_singleton()->send_message("remote_nodes_clicked", message);
+		EngineDebugger::get_singleton()->send_message("remote_objects_selected", message);
 		_set_selected_nodes(picked_nodes);
 
 		return;
@@ -1778,7 +1778,7 @@ void RuntimeNodeSelect::_send_ids(const Vector<Node *> &p_picked_nodes, bool p_i
 	}
 
 	if (ids.is_empty()) {
-		EngineDebugger::get_singleton()->send_message("remote_nothing_clicked", message);
+		EngineDebugger::get_singleton()->send_message("remote_nothing_selected", message);
 	} else {
 		for (const ObjectID &id : ids) {
 			SceneDebuggerObject obj(id);
@@ -1787,7 +1787,7 @@ void RuntimeNodeSelect::_send_ids(const Vector<Node *> &p_picked_nodes, bool p_i
 			message.append(arr);
 		}
 
-		EngineDebugger::get_singleton()->send_message("remote_nodes_clicked", message);
+		EngineDebugger::get_singleton()->send_message("remote_objects_selected", message);
 	}
 
 	_set_selected_nodes(nodes);


Test patch: