Repository: godotengine/godot (language: cpp)

Issue:
Exported project fails to start when UID is saved in project settings
### Tested versions

- Reproducible in Godot master (c2e4ae782a399adf42c664d3d21d8defe49ba8e5)

### System information

Windows 10

### Issue description

If you set the main scene through the project manager dialog Godot now saves the UID in the project file:
```
config_version=5

[application]

config/name="test-export"
run/main_scene="uid://dg450amr7gaby"
config/features=PackedStringArray("4.4", "GL Compatibility")
config/icon="res://icon.svg"
```

This works fine in the editor but after exporting your project, Godot can no longer run the project:
```
PS C:\projects\export> Godot Engine v4.4.dev.custom_build.c2e4ae782 (2024-12-11 17:48:18 UTC) - https://godotengine.org
OpenGL API 3.3.0 NVIDIA 566.03 - Compatibility - Using Device: NVIDIA - NVIDIA GeForce RTX 4070 Ti

ERROR: No loader found for resource: res://uid:/dg450amr7gaby (expected type: )
   at: (core\io\resource_loader.cpp:327)
ERROR: Failed loading scene: res://uid:/dg450amr7gaby.
   at: (main\main.cpp:4214)
```

The fault is caused by this line of code:
```
editor_node.cpp:3973 if (!p_force_open_imported && FileAccess::exists(p_scene + ".import")) {
```
It attempts to load the file `res://uid:/dg450amr7gaby.import` which does not exist.

### Steps to reproduce

- Create a new project
- Create a scene, add some stuff to it
- Save the scene
- Select the scene as your main scene in the project manager (IMPORTANT, If you run your scene and select "use current scene" it will save the proper file path and work)
- Export your project

### Minimal reproduction project (MRP)

[test-export.zip](https://github.com/user-attachments/files/18125819/test-export.zip)



Discussion / hints:
> The fault is caused by this line of code:
editor_node.cpp:3973 if (!p_force_open_imported && FileAccess::exists(p_scene + ".import")) {

How can it cause the bug if it's editor code?
> > The fault is caused by this line of code:
> > editor_node.cpp:3973 if (!p_force_open_imported && FileAccess::exists(p_scene + ".import")) {
> 
> How can it cause the bug if it's editor code?

I presume it means the export step is doing something wrong, and thus the resulting PCK is invalid and different from if there was no bug.
Then the error would appear during export, but it's not the case.
There are two issues here and the description is mixed up. The quoted line causes error on editor startup, if no scene was restored (so it tries to open main scene)
Owh that last bit might be a fluke of testing on my end, I might have run it with a dev/editor build to try and trap the error as with a runtime build it just quits silently.

The bottom line is:
- exporting the project with the UIDs in the `project.godot` file -> exported project fails to load and just quits
- editing the `project.godot` to add proper paths (or select "use current scene" when running a project) -> exported project works
Just to rule out there is an issue with my custom build. Just reproduced this with Godot 4.4 dev 6 with the following steps:

1. Download Godot 4.4 dev 6 and run
2. Create a new project
3. Download export templats
4. Create a new scene, add `DirectionalLight3D`, `WorldEnvironment`, `Camera3D` and `MeshInstance3D` with a `BoxMesh` to create the most basic scene possible
5. Save this scene
6. Open project manager, select Run, set the main scene to the scene you just saved
7. Press run button in toolbar to test, project works
8. Open export window
9. Add `Windows Desktop` export preset
10. Press Export Project and save the project in a new folder
11. Run the exported project, project fails to load.
Just a detail, this seems to be a duplicate of #100084 but this one has more detail, maybe is good consolidate everything here or at least keep an eye to close both when the fix is done.

Fix patch:
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 7591208aa02c..d89593b5aeb0 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -2085,7 +2085,7 @@ void EditorNode::_dialog_action(String p_file) {
 			load_scene(p_file);
 		} break;
 		case SETTINGS_PICK_MAIN_SCENE: {
-			ProjectSettings::get_singleton()->set("application/run/main_scene", p_file);
+			ProjectSettings::get_singleton()->set("application/run/main_scene", ResourceUID::path_to_uid(p_file));
 			ProjectSettings::get_singleton()->save();
 			// TODO: Would be nice to show the project manager opened with the highlighted field.
 
@@ -2134,7 +2134,7 @@ void EditorNode::_dialog_action(String p_file) {
 		} break;
 
 		case FILE_SAVE_AND_RUN_MAIN_SCENE: {
-			ProjectSettings::get_singleton()->set("application/run/main_scene", p_file);
+			ProjectSettings::get_singleton()->set("application/run/main_scene", ResourceUID::path_to_uid(p_file));
 			ProjectSettings::get_singleton()->save();
 
 			if (file->get_file_mode() == EditorFileDialog::FILE_MODE_SAVE_FILE) {
@@ -3962,25 +3962,25 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b
 		return OK;
 	}
 
+	String lpath = ResourceUID::ensure_path(p_scene);
 	if (!p_set_inherited) {
 		for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
-			if (editor_data.get_scene_path(i) == p_scene) {
+			if (editor_data.get_scene_path(i) == lpath) {
 				_set_current_scene(i);
 				return OK;
 			}
 		}
 
-		if (!p_force_open_imported && FileAccess::exists(p_scene + ".import")) {
-			open_imported->set_text(vformat(TTR("Scene '%s' was automatically imported, so it can't be modified.\nTo make changes to it, a new inherited scene can be created."), p_scene.get_file()));
+		if (!p_force_open_imported && FileAccess::exists(lpath + ".import")) {
+			open_imported->set_text(vformat(TTR("Scene '%s' was automatically imported, so it can't be modified.\nTo make changes to it, a new inherited scene can be created."), lpath.get_file()));
 			open_imported->popup_centered();
 			new_inherited_button->grab_focus();
-			open_import_request = p_scene;
+			open_import_request = lpath;
 			return OK;
 		}
 	}
 
-	String lpath = ProjectSettings::get_singleton()->localize_path(p_scene);
-
+	lpath = ProjectSettings::get_singleton()->localize_path(lpath);
 	if (!lpath.begins_with("res://")) {
 		show_accept(TTR("Error loading scene, it must be inside the project path. Use 'Import' to open the scene, then save it inside the project path."), TTR("OK"));
 		opening_prev = false;
@@ -4081,7 +4081,7 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b
 
 	set_edited_scene(new_scene);
 
-	String config_file_path = EditorPaths::get_singleton()->get_project_settings_dir().path_join(p_scene.get_file() + "-editstate-" + p_scene.md5_text() + ".cfg");
+	String config_file_path = EditorPaths::get_singleton()->get_project_settings_dir().path_join(lpath.get_file() + "-editstate-" + lpath.md5_text() + ".cfg");
 	Ref<ConfigFile> editor_state_cf;
 	editor_state_cf.instantiate();
 	Error editor_state_cf_err = editor_state_cf->load(config_file_path);
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 9bf21a543884..ac95f0346d56 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -270,7 +270,7 @@ void FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
 
 	// Create all items for the files in the subdirectory.
 	if (display_mode == DISPLAY_MODE_TREE_ONLY) {
-		String main_scene = GLOBAL_GET("application/run/main_scene");
+		const String main_scene = ResourceUID::ensure_path(GLOBAL_GET("application/run/main_scene"));
 
 		// Build the list of the files to display.
 		List<FileInfo> file_list;
@@ -1125,7 +1125,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
 	sort_file_info_list(file_list, file_sort);
 
 	// Fills the ItemList control node from the FileInfos.
-	String main_scene = GLOBAL_GET("application/run/main_scene");
+	const String main_scene = ResourceUID::ensure_path(GLOBAL_GET("application/run/main_scene"));
 	for (FileInfo &E : file_list) {
 		FileInfo *finfo = &(E);
 		String fname = finfo->name;
@@ -2379,7 +2379,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
 		case FILE_MAIN_SCENE: {
 			// Set as main scene with selected scene file.
 			if (p_selected.size() == 1) {
-				ProjectSettings::get_singleton()->set("application/run/main_scene", p_selected[0]);
+				ProjectSettings::get_singleton()->set("application/run/main_scene", ResourceUID::path_to_uid(p_selected[0]));
 				ProjectSettings::get_singleton()->save();
 				_update_tree(get_uncollapsed_paths());
 				_update_file_list(true);
diff --git a/main/main.cpp b/main/main.cpp
index b3b6d960e7a1..b8dec2154b24 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -3817,8 +3817,8 @@ int Main::start() {
 
 #endif // TOOLS_ENABLED
 
-	if (script.is_empty() && game_path.is_empty() && String(GLOBAL_GET("application/run/main_scene")) != "") {
-		game_path = GLOBAL_GET("application/run/main_scene");
+	if (script.is_empty() && game_path.is_empty()) {
+		game_path = ResourceUID::ensure_path(GLOBAL_GET("application/run/main_scene"));
 	}
 
 #ifdef TOOLS_ENABLED


Test patch: