Repository: godotengine/godot (language: cpp)

Issue:
Restarting Godot from Editor Settings might discard unsaved scenes
<!-- Please search existing issues for potential duplicates before filing yours:
https://github.com/godotengine/godot/issues?q=is%3Aissue
-->

**Godot version:**
<!-- Specify commit hash if using non-official build. -->
3.2.3

**Steps to reproduce:**
1. Create a new scene (don't save it)
2. Do some changes
3. Go do editor settings and change something that requires restart (e.g. display scale)
4. Click the Save and Restart prompt
5. The editor gets restarted, but the scene is not being saved


Discussion / hints:
Hi. So I've been looking at this and from what I can tell, when the Save & Restart button is pressed, only the EditorNode::_save_all_scenes() is called, which specifically states it ignores new scenes. Whereas if you have a new scene and try to quit the editor, EditorNode::_menu_option_confirm(FILE_CLOSE_ALL_AND_QUIT, false) is called which takes care of saving the new scene. 
Open question: Should _save_all_scenes()  just include the saving or new scenes as well, or should the restart button just additionally call the _menu_option_confirm function? I did try adding _menu_option_confirm, but although technically the dialog with popup, the editor would restart without waiting for a response, and I'm still trying to understand the whole event system.

This is my first time trying to contribute to open source projects, so any feedback or suggestions would be appreciated.
@Nickswoboda I think it would be better if you looked into issues labelled with "Junior Job", as they are better suited for the first contribution. This one isn't really obvious in how it should be fixed. Perfectly the user should be asked if they want to save the scene and if they confirm, choose the file after which the scene saves and editor closes. But I can't tell exactly how it can be achieved or what should be used, without looking into the problem. Which is why I haven't labelled this issue as "Junior Job".

Another thing is that scene saving in the editor isn't really consistent (#40539)
Hey, this is still happening. Just lost a scene.

Fix patch:
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 84a4b42f5363..6b725240f9e2 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -2057,45 +2057,7 @@ void EditorNode::try_autosave() {
 }
 
 void EditorNode::restart_editor(bool p_goto_project_manager) {
-	exiting = true;
-
-	if (project_run_bar->is_playing()) {
-		project_run_bar->stop_playing();
-	}
-
-	String to_reopen;
-	if (!p_goto_project_manager && get_tree()->get_edited_scene_root()) {
-		to_reopen = get_tree()->get_edited_scene_root()->get_scene_file_path();
-	}
-
-	_exit_editor(EXIT_SUCCESS);
-
-	List<String> args;
-	for (const String &a : Main::get_forwardable_cli_arguments(Main::CLI_SCOPE_TOOL)) {
-		args.push_back(a);
-	}
-
-	if (p_goto_project_manager) {
-		args.push_back("--project-manager");
-
-		// Setup working directory.
-		const String exec_dir = OS::get_singleton()->get_executable_path().get_base_dir();
-		if (!exec_dir.is_empty()) {
-			args.push_back("--path");
-			args.push_back(exec_dir);
-		}
-	} else {
-		args.push_back("--path");
-		args.push_back(ProjectSettings::get_singleton()->get_resource_path());
-
-		args.push_back("-e");
-	}
-
-	if (!to_reopen.is_empty()) {
-		args.push_back(to_reopen);
-	}
-
-	OS::get_singleton()->set_restart_on_exit(true, args);
+	_menu_option_confirm(p_goto_project_manager ? PROJECT_QUIT_TO_PROJECT_MANAGER : PROJECT_RELOAD_CURRENT_PROJECT, false);
 }
 
 void EditorNode::_save_all_scenes() {
@@ -3480,10 +3442,10 @@ void EditorNode::_discard_changes(const String &p_str) {
 
 		} break;
 		case PROJECT_QUIT_TO_PROJECT_MANAGER: {
-			restart_editor(true);
+			_restart_editor(true);
 		} break;
 		case PROJECT_RELOAD_CURRENT_PROJECT: {
-			restart_editor();
+			_restart_editor();
 		} break;
 	}
 }
@@ -5508,11 +5470,11 @@ bool EditorNode::has_scenes_in_session() {
 }
 
 void EditorNode::undo() {
-	trigger_menu_option(FILE_UNDO, true);
+	_menu_option_confirm(FILE_UNDO, true);
 }
 
 void EditorNode::redo() {
-	trigger_menu_option(FILE_REDO, true);
+	_menu_option_confirm(FILE_REDO, true);
 }
 
 bool EditorNode::ensure_main_scene(bool p_from_native) {
@@ -5680,6 +5642,48 @@ bool EditorNode::_is_closing_editor() const {
 	return tab_closing_menu_option == FILE_QUIT || tab_closing_menu_option == PROJECT_QUIT_TO_PROJECT_MANAGER || tab_closing_menu_option == PROJECT_RELOAD_CURRENT_PROJECT;
 }
 
+void EditorNode::_restart_editor(bool p_goto_project_manager) {
+	exiting = true;
+
+	if (project_run_bar->is_playing()) {
+		project_run_bar->stop_playing();
+	}
+
+	String to_reopen;
+	if (!p_goto_project_manager && get_tree()->get_edited_scene_root()) {
+		to_reopen = get_tree()->get_edited_scene_root()->get_scene_file_path();
+	}
+
+	_exit_editor(EXIT_SUCCESS);
+
+	List<String> args;
+	for (const String &a : Main::get_forwardable_cli_arguments(Main::CLI_SCOPE_TOOL)) {
+		args.push_back(a);
+	}
+
+	if (p_goto_project_manager) {
+		args.push_back("--project-manager");
+
+		// Setup working directory.
+		const String exec_dir = OS::get_singleton()->get_executable_path().get_base_dir();
+		if (!exec_dir.is_empty()) {
+			args.push_back("--path");
+			args.push_back(exec_dir);
+		}
+	} else {
+		args.push_back("--path");
+		args.push_back(ProjectSettings::get_singleton()->get_resource_path());
+
+		args.push_back("-e");
+	}
+
+	if (!to_reopen.is_empty()) {
+		args.push_back(to_reopen);
+	}
+
+	OS::get_singleton()->set_restart_on_exit(true, args);
+}
+
 void EditorNode::_scene_tab_closed(int p_tab) {
 	current_menu_option = SCENE_TAB_CLOSE;
 	tab_closing_idx = p_tab;
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 3ace2e868c5b..de3af997473a 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -624,6 +624,7 @@ class EditorNode : public Node {
 
 	void _proceed_closing_scene_tabs();
 	bool _is_closing_editor() const;
+	void _restart_editor(bool p_goto_project_manager = false);
 
 	Dictionary _get_main_scene_state();
 	void _set_main_scene_state(Dictionary p_state, Node *p_for_scene);


Test patch: