Skip to content
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 "Safe Mode" for recovering crashing projects during initialization #92563

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions core/config/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ class Engine {
bool editor_hint = false;
bool project_manager_hint = false;
bool extension_reloading = false;
bool safe_mode_hint = false;

bool _print_header = true;

Expand Down Expand Up @@ -156,6 +157,9 @@ class Engine {

_FORCE_INLINE_ void set_extension_reloading_enabled(bool p_enabled) { extension_reloading = p_enabled; }
_FORCE_INLINE_ bool is_extension_reloading_enabled() const { return extension_reloading; }

_FORCE_INLINE_ void set_safe_mode_hint(bool p_enabled) { safe_mode_hint = p_enabled; }
_FORCE_INLINE_ bool is_safe_mode_hint() const { return safe_mode_hint; }
#else
_FORCE_INLINE_ void set_editor_hint(bool p_enabled) {}
_FORCE_INLINE_ bool is_editor_hint() const { return false; }
Expand All @@ -165,6 +169,9 @@ class Engine {

_FORCE_INLINE_ void set_extension_reloading_enabled(bool p_enabled) {}
_FORCE_INLINE_ bool is_extension_reloading_enabled() const { return false; }

_FORCE_INLINE_ void set_safe_mode_hint(bool p_enabled) {}
_FORCE_INLINE_ bool is_safe_mode_hint() const { return false; }
#endif

Dictionary get_version_info() const;
Expand Down
27 changes: 27 additions & 0 deletions core/extension/gdextension_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ GDExtensionManager::LoadStatus GDExtensionManager::_unload_extension_internal(co
}

GDExtensionManager::LoadStatus GDExtensionManager::load_extension(const String &p_path) {
if (Engine::get_singleton()->is_safe_mode_hint()) {
return LOAD_STATUS_OK;
}

Ref<GDExtensionLibraryLoader> loader;
loader.instantiate();
return GDExtensionManager::get_singleton()->load_extension_with_loader(p_path, loader);
Expand Down Expand Up @@ -119,6 +123,10 @@ GDExtensionManager::LoadStatus GDExtensionManager::reload_extension(const String
#else
ERR_FAIL_COND_V_MSG(!Engine::get_singleton()->is_extension_reloading_enabled(), LOAD_STATUS_FAILED, "GDExtension reloading is disabled.");

if (Engine::get_singleton()->is_safe_mode_hint()) {
return LOAD_STATUS_OK;
}

if (!gdextension_map.has(p_path)) {
return LOAD_STATUS_NOT_LOADED;
}
Expand Down Expand Up @@ -161,6 +169,10 @@ GDExtensionManager::LoadStatus GDExtensionManager::reload_extension(const String
}

GDExtensionManager::LoadStatus GDExtensionManager::unload_extension(const String &p_path) {
if (Engine::get_singleton()->is_safe_mode_hint()) {
return LOAD_STATUS_OK;
}

if (!gdextension_map.has(p_path)) {
return LOAD_STATUS_NOT_LOADED;
}
Expand Down Expand Up @@ -207,6 +219,10 @@ String GDExtensionManager::class_get_icon_path(const String &p_class) const {
}

void GDExtensionManager::initialize_extensions(GDExtension::InitializationLevel p_level) {
if (Engine::get_singleton()->is_safe_mode_hint()) {
return;
}

ERR_FAIL_COND(int32_t(p_level) - 1 != level);
for (KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
E.value->initialize_library(p_level);
Expand All @@ -215,6 +231,10 @@ void GDExtensionManager::initialize_extensions(GDExtension::InitializationLevel
}

void GDExtensionManager::deinitialize_extensions(GDExtension::InitializationLevel p_level) {
if (Engine::get_singleton()->is_safe_mode_hint()) {
return;
}

ERR_FAIL_COND(int32_t(p_level) != level);
for (KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
E.value->deinitialize_library(p_level);
Expand Down Expand Up @@ -253,6 +273,10 @@ void GDExtensionManager::_reload_all_scripts() {
#endif // TOOLS_ENABLED

void GDExtensionManager::load_extensions() {
if (Engine::get_singleton()->is_safe_mode_hint()) {
return;
}

Ref<FileAccess> f = FileAccess::open(GDExtension::get_extension_list_config_file(), FileAccess::READ);
while (f.is_valid() && !f->eof_reached()) {
String s = f->get_line().strip_edges();
Expand All @@ -267,6 +291,9 @@ void GDExtensionManager::load_extensions() {

void GDExtensionManager::reload_extensions() {
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_safe_mode_hint()) {
return;
}
bool reloaded = false;
for (const KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
if (!E.value->is_reloadable()) {
Expand Down
23 changes: 22 additions & 1 deletion core/os/os.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,10 +287,14 @@ String OS::get_bundle_icon_path() const {
}

// OS specific path for user://
String OS::get_user_data_dir() const {
String OS::get_user_data_dir(const String &p_appname) const {
return ".";
}

String OS::get_user_data_dir() const {
return get_user_data_dir(get_safe_dir_name(GLOBAL_GET("application/config/name")));
}

// Absolute path to res://
String OS::get_resource_dir() const {
return ProjectSettings::get_singleton()->get_resource_path();
Expand All @@ -301,6 +305,23 @@ String OS::get_system_dir(SystemDir p_dir, bool p_shared_storage) const {
return ".";
}

void OS::create_lock_file() {
if (Engine::get_singleton()->is_safe_mode_hint()) {
return;
}

String lock_file_path = get_user_data_dir().path_join(".safe_mode_lock");
Ref<FileAccess> lock_file = FileAccess::open(lock_file_path, FileAccess::WRITE);
if (lock_file.is_valid()) {
lock_file->close();
}
}

void OS::remove_lock_file() {
String lock_file_path = get_user_data_dir().path_join(".safe_mode_lock");
DirAccess::remove_absolute(lock_file_path);
}

Error OS::shell_open(const String &p_uri) {
return ERR_UNAVAILABLE;
}
Expand Down
4 changes: 4 additions & 0 deletions core/os/os.h
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ class OS {
virtual String get_bundle_resource_dir() const;
virtual String get_bundle_icon_path() const;

virtual String get_user_data_dir(const String &p_appname) const;
virtual String get_user_data_dir() const;
virtual String get_resource_dir() const;

Expand All @@ -296,6 +297,9 @@ class OS {

virtual Error move_to_trash(const String &p_path) { return FAILED; }

void create_lock_file();
void remove_lock_file();

virtual int get_exit_code() const;
// `set_exit_code` should only be used from `SceneTree` (or from a similar
// level, e.g. from the `Main::start` if leaving without creating a `SceneTree`).
Expand Down
9 changes: 4 additions & 5 deletions drivers/unix/os_unix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -872,18 +872,17 @@ void OS_Unix::unset_environment(const String &p_var) const {
unsetenv(p_var.utf8().get_data());
}

String OS_Unix::get_user_data_dir() const {
String appname = get_safe_dir_name(GLOBAL_GET("application/config/name"));
if (!appname.is_empty()) {
String OS_Unix::get_user_data_dir(const String &p_appname) const {
if (!p_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;
custom_dir = p_appname;
}
return get_data_path().path_join(custom_dir);
} else {
return get_data_path().path_join(get_godot_dir_name()).path_join("app_userdata").path_join(appname);
return get_data_path().path_join(get_godot_dir_name()).path_join("app_userdata").path_join(p_appname);
}
}

Expand Down
2 changes: 1 addition & 1 deletion drivers/unix/os_unix.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class OS_Unix : public OS {
virtual void initialize_debugging() override;

virtual String get_executable_path() const override;
virtual String get_user_data_dir() const override;
virtual String get_user_data_dir(const String &p_appname) const override;
};

class UnixTerminalLogger : public StdLogger {
Expand Down
8 changes: 8 additions & 0 deletions editor/debugger/editor_debugger_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ EditorDebuggerNode::EditorDebuggerNode() {
remote_scene_tree_timeout = EDITOR_GET("debugger/remote_scene_tree_refresh_interval");
inspect_edited_object_timeout = EDITOR_GET("debugger/remote_inspect_refresh_interval");

if (Engine::get_singleton()->is_safe_mode_hint()) {
return;
}

EditorRunBar::get_singleton()->get_pause_button()->connect(SceneStringName(pressed), callable_mp(this, &EditorDebuggerNode::_paused));
}

Expand Down Expand Up @@ -262,6 +266,10 @@ void EditorDebuggerNode::set_keep_open(bool p_keep_open) {
}

Error EditorDebuggerNode::start(const String &p_uri) {
if (Engine::get_singleton()->is_safe_mode_hint()) {
return OK;
}

ERR_FAIL_COND_V(!p_uri.contains("://"), ERR_INVALID_PARAMETER);
if (keep_open && current_uri == p_uri && server.is_valid()) {
return OK;
Expand Down
14 changes: 14 additions & 0 deletions editor/editor_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,10 @@ void EditorNode::_notification(int p_what) {
CanvasItemEditor::ThemePreviewMode theme_preview_mode = (CanvasItemEditor::ThemePreviewMode)(int)EditorSettings::get_singleton()->get_project_metadata("2d_editor", "theme_preview", CanvasItemEditor::THEME_PREVIEW_PROJECT);
update_preview_themes(theme_preview_mode);

if (Engine::get_singleton()->is_safe_mode_hint()) {
EditorToaster::get_singleton()->popup_str(TTR("Safe Mode is enabled. Editor functionality has been restricted."), EditorToaster::SEVERITY_WARNING);
}

/* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */
} break;

Expand Down Expand Up @@ -1150,9 +1154,15 @@ void EditorNode::_sources_changed(bool p_exist) {
if (!singleton->cmdline_export_mode) {
EditorResourcePreview::get_singleton()->start();
}

get_tree()->create_timer(1.0f)->connect("timeout", callable_mp(this, &EditorNode::_remove_lock_file));
}
}

void EditorNode::_remove_lock_file() {
OS::get_singleton()->remove_lock_file();
}

void EditorNode::_scan_external_changes() {
disk_changed_list->clear();
TreeItem *r = disk_changed_list->create_item();
Expand Down Expand Up @@ -5346,6 +5356,10 @@ void EditorNode::_save_window_settings_to_config(Ref<ConfigFile> p_layout, const
}

void EditorNode::_load_open_scenes_from_config(Ref<ConfigFile> p_layout) {
if (Engine::get_singleton()->is_safe_mode_hint()) {
return;
}

if (!bool(EDITOR_GET("interface/scene_tabs/restore_scenes_on_load"))) {
return;
}
Expand Down
29 changes: 15 additions & 14 deletions editor/editor_node.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,20 +132,6 @@ class EditorNode : public Node {
ACTION_ON_STOP_CLOSE_BUTTOM_PANEL,
};

struct ExecuteThreadArgs {
String path;
List<String> args;
String output;
Thread execute_output_thread;
Mutex execute_output_mutex;
int exitcode = 0;
SafeFlag done;
};

private:
friend class EditorSceneTabs;
friend class SurfaceUpgradeTool;

enum MenuOptions {
FILE_NEW_SCENE,
FILE_NEW_INHERITED_SCENE,
Expand Down Expand Up @@ -235,6 +221,20 @@ class EditorNode : public Node {
TOOL_MENU_BASE = 1000
};

struct ExecuteThreadArgs {
String path;
List<String> args;
String output;
Thread execute_output_thread;
Mutex execute_output_mutex;
int exitcode = 0;
SafeFlag done;
};

private:
friend class EditorSceneTabs;
friend class SurfaceUpgradeTool;

enum {
MAX_INIT_CALLBACKS = 128,
MAX_BUILD_CALLBACKS = 128
Expand Down Expand Up @@ -543,6 +543,7 @@ class EditorNode : public Node {
void _resources_reimporting(const Vector<String> &p_resources);
void _resources_reimported(const Vector<String> &p_resources);
void _sources_changed(bool p_exist);
void _remove_lock_file();

void _node_renamed();
void _save_editor_states(const String &p_file, int p_idx = -1);
Expand Down
Loading
Loading