-
-
Notifications
You must be signed in to change notification settings - Fork 21.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement a "Recovery Mode" for recovering crashing projects during initialization #92563
base: master
Are you sure you want to change the base?
Conversation
Is the yellow border for the safe mode dialog necessary? It won't even be seen by most since windows aren't embedded by default in the editor. |
Good point, I don't use the default setting of separated windows 😅 It was more of an experiment, but I believe the yellow banner at the run bar is already noticeable enough 👍 |
7311717
to
88f7e17
Compare
Note that we could automatically prompt the user to edit a project in safe mode after an editor (not project) crash. To do so, we need to write a file in the project's When opening any project, the editor checks for the presence of this file. If the file is present, a dialog is spawned to prompt the user to open the project in safe mode. Regardless of the user's answer, the file is removed afterwards when the editor is done initializing and rescanning things. When opening a project from the command line, the project opens as usual, but a warning message is printed to warn the user that they can use After doing this, we probably won't need to have the Edit (Safe Mode) button anymore in the project manager (which I feel is too prominent right now). We could make it manually accessible by shift-clicking, but I think the automatic prompt will suit the 90% use case. A similar approach could be used to write a "lock file" in |
ea34c06
to
5e79eab
Compare
@Calinou yes, I think this an important mechanism to complement this feature. I hadn't included it yet because, actually, I wanted to confirm this detail that you've mentioned, before proceeding:
Do we really want this mode to be triggered on any editor crash? I think it would generate more false positives (e.g. internal engine crashes) and generate user confusion because this mode would implicitly be triggered for all types of crashes, when it can only help in troubleshooting a subset of them. I'm more concerned in ensuring we avoid false positives, and limiting this mode to only trigger on initialization crashes helps to reduce that. The usefulness of this mode, in my opinion, is tied to situations where a user lost the ability to edit the project at all and requires some form of external intervention to recover them. |
Maybe we could create some "init" file when starting editor and delete it once the editor loads. If it doesn't load it means it crashed. |
5e79eab
to
c292649
Compare
@KoBeWi should I add the auto-detect crash functionality we discussed already in this PR, or do it in another PR after this one is merged? I think @Calinou brings a valid point in doing it right now; if this functionality is implemented, there isn't much need to add the new "Edit in Safe Mode" button to the project manager. I don't expect this functionality to take much effort to implement, but considering my current availability, it might still take around one week to implement. |
Well, this is not going to be merged before 4.4, so you have some time to improve it. |
You renamed |
Yes, that was intended; I renamed Since you're doing something similar, I saw fit to also rename it to |
But the function performs the migration. The checks are technically done before the info dialog appears. |
8990cbd
to
8faa6f2
Compare
Ok yeah, you're right, I've reverted this name change. |
0111dd7
to
015a1e7
Compare
015a1e7
to
47721c4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
47721c4
to
23ecaab
Compare
I rebased to solve merge conflicts. I'll try to find a bit of time to finally test the feature and approve. |
return Item(project_name, description, project_version, tags, p_path, icon, main_scene, unsupported_features, last_edited, p_favorite, grayed, missing, config_version); | ||
// We can't use globalize_path because there is no loaded project. So we replicate the behavior of accessing user:// | ||
if (!cf_project_name.is_empty()) { | ||
String safe_mode_lock_file = OS::get_singleton()->get_user_data_dir(cf_project_name).path_join(".safe_mode_lock"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't it do get_safe_dir_name
on a name, like it's done in the actualt project, also seems like it won't handle application/config/use_custom_user_dir
/application/config/custom_user_dir_name
override (get_user_data_dir
is reading it from currently loaded config, but in this case it should be selected project config).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't it do get_safe_dir_name on a name, like it's done in the actualt project,
Yup, I missed that. I also don't remember why I used the raw cf_project_name
variable instead of the unescaped project_name
, so I'll revisit this.
also seems like it won't handle application/config/use_custom_user_dir/application/config/custom_user_dir_name override
This is indeed a problem, because this query is inside the get_user_dir
. I already had to move the query for application/config/name
outside to be able to set it from the context of the project manager. My best idea so far is to extract all project specific logic from this function, and move this logic to the generic os.cpp::get_user_data_dir()
function, with the OS-specific overrides now becoming quite simple:
// os.cpp
String OS::get_user_data_dir() const {
String appname = get_safe_dir_name(GLOBAL_GET("application/config/name"));
if (!appname.is_empty()) {
bool use_custom_dir = GLOBAL_GET("application/config/use_custom_user_dir");
if (use_custom_dir) {
String custom_dir = get_safe_dir_name(GLOBAL_GET("application/config/custom_user_dir_name"), true);
if (custom_dir.is_empty()) {
custom_dir = appname;
}
return get_user_data_dir(custom_dir);
} else {
return get_user_data_dir(get_godot_dir_name().path_join("app_userdata").path_join(appname));
}
}
return get_user_data_dir(get_godot_dir_name().path_join("app_userdata").path_join("[unnamed project]"));
}
...
// os_unix.cpp
String OS_Unix::get_user_data_dir(const String &p_dirname) const {
return get_data_path().path_join(p_dirname);
}
...
// os_windows.cpp
String OS_Unix::get_user_data_dir(const String &p_dirname) const {
return get_data_path().path_join(p_dirname).replace("\\", "/");
}
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ended up extracting this logic to os.cpp
, which has the benefit of unifying 3 implementations (Unix, Windows and Web).
Tested briefly with the MRP of #99001 which causes a crash on start from a tool script, and with this PR it's properly flagged as requiring Safe Mode, which works well to open the project and then manually fix the tool script. Also tested with a 4.1 project where I'd install godot-jolt 0.8.0 (known to crash on 4.2+), which crashes when opened with One minor nitpick, when you manually select Edit in Safe Mode from the Project Manager for any project, it shows the same dialog as if that project did crash previously, so it starts with: This isn't accurate if selecting Safe Mode manually on projects that didn't crash. |
Good catch! I'll hide that part of the message when this is triggered manually then 👍 |
Sorry for being very late to the party, I think the term I suggest to rename the option as |
Huum I agree, it does a better job at conveying that this mode is mostly intended as a "rescue" mode, not as a slightly less functional but still usable mode for development. I'll change the naming and fix the merge conflict that appeared in the meantime 👍 |
1161b2f
to
1fce89c
Compare
I've made some significant changes this time, so here's a summary (the original description will be updated shortly too):
And some minor changes I took the liberty of doing as well:
|
…during initialization
1fce89c
to
f87f54c
Compare
Implements godotengine/godot-proposals#2628
Note
This description is updated whenever any significant changes are made, and should always reflect the current state of this PR
Overview
This adds a new special "Recovery Mode" that, as described, disables some engine features that can make a project fail to launch during startup. When this mode is launched, the following features are completely disabled:
This is displayed to the user as soon as the project is opened in this mode, through both a popup, and a notification:
Because some of these features may be necessary for a project to work properly, this mode may put the project in an unusable/unworkable state. Since this is a temporary mode meant to allow only for some basic troubleshooting, a few other changes were done as well to reflect this:
Usage
Automatic detection
When launching a project, Godot creates a lock file at
user://.recovery_mode_lock
. This file persists during the engine initialization, and is removed when the editor starts scanning the project files, after one second.If any crash/hang happens during initialization, this file is not removed. So, if this file exists the next time Godot attempts to open the project, then the engine knows the project failed to open last time, thus prompting the user to open it in this mode.
CLI
This mode can be manually triggered by opening a project with the new
--recovery-mode
flag:UI
When a project is opened, the project manager searches for any existing lock file; if that's the case, it opens a popup to suggest using this mode, explaining what it does and its intended usage.
It is also possible to use this mode manually from the new options button next to the Edit button:
Test projects
To test this functionality, I've made a test suite of projects that crash the engine on initialization with typical user scenarios:
All of these test cases fail to open on a normal Godot session and require manual intervention to be recovered. But under recovery mode, every test must open successfully.
Future work
This is a basic implementation so far, and the usefulness of this mode should be improved with other additional features:
An automatic mechanism to detect failing scenarios and automatically prompt users to enable this mode, as described in Add a way to disable all plugins when opening a project (safe mode) godot-proposals#2628(edit: implemented in this PR too)