diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 6d28b9abc84..d17a1ccecc1 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -623,6 +623,20 @@ void EditorNode::_notification(int p_what) { ResourceImporterTexture::get_singleton()->update_imports(); bottom_panel_updating = false; + + if (requested_first_scan) { + requested_first_scan = false; + + OS::get_singleton()->benchmark_begin_measure("editor_scan_and_import"); + + if (run_surface_upgrade_tool) { + run_surface_upgrade_tool = false; + SurfaceUpgradeTool::get_singleton()->connect("upgrade_finished", callable_mp(EditorFileSystem::get_singleton(), &EditorFileSystem::scan), CONNECT_ONE_SHOT); + SurfaceUpgradeTool::get_singleton()->finish_upgrade(); + } else { + EditorFileSystem::get_singleton()->scan(); + } + } } break; case NOTIFICATION_ENTER_TREE: { @@ -1042,6 +1056,10 @@ void EditorNode::_sources_changed(bool p_exist) { OS::get_singleton()->benchmark_dump(); } + + if (SurfaceUpgradeTool::get_singleton()->is_show_requested()) { + SurfaceUpgradeTool::get_singleton()->show_popup(); + } } } @@ -4615,8 +4633,10 @@ void EditorNode::_editor_file_dialog_unregister(EditorFileDialog *p_dialog) { Vector EditorNode::_init_callbacks; void EditorNode::_begin_first_scan() { - OS::get_singleton()->benchmark_begin_measure("editor_scan_and_import"); - EditorFileSystem::get_singleton()->scan(); + if (!waiting_for_first_scan) { + return; + } + requested_first_scan = true; } Error EditorNode::export_preset(const String &p_preset, const String &p_path, bool p_debug, bool p_pack_only) { @@ -6809,6 +6829,13 @@ EditorNode::EditorNode() { FileAccess::set_backup_save(EDITOR_GET("filesystem/on_save/safe_save_on_backup_then_rename")); + // Warm up the surface upgrade tool as early as possible. + surface_upgrade_tool = memnew(SurfaceUpgradeTool); + run_surface_upgrade_tool = EditorSettings::get_singleton()->get_project_metadata("surface_upgrade_tool", "run_on_restart", false); + if (run_surface_upgrade_tool) { + SurfaceUpgradeTool::get_singleton()->begin_upgrade(); + } + { int display_scale = EDITOR_GET("interface/editor/display_scale"); @@ -8051,8 +8078,6 @@ EditorNode::EditorNode() { String exec = OS::get_singleton()->get_executable_path(); // Save editor executable path for third-party tools. EditorSettings::get_singleton()->set_project_metadata("editor_metadata", "executable_path", exec); - - surface_upgrade_tool = memnew(SurfaceUpgradeTool); } EditorNode::~EditorNode() { diff --git a/editor/editor_node.h b/editor/editor_node.h index b2fb03be6ba..fe99cf1f010 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -157,6 +157,7 @@ public: private: friend class EditorSceneTabs; + friend class SurfaceUpgradeTool; enum MenuOptions { FILE_NEW_SCENE, @@ -459,6 +460,8 @@ private: bool opening_prev = false; bool restoring_scenes = false; bool unsaved_cache = true; + + bool requested_first_scan = false; bool waiting_for_first_scan = true; int current_menu_option = 0; @@ -493,6 +496,7 @@ private: HashMap> icon_type_cache; SurfaceUpgradeTool *surface_upgrade_tool = nullptr; + bool run_surface_upgrade_tool = false; static EditorBuildCallback build_callbacks[MAX_BUILD_CALLBACKS]; static EditorPluginInitializeCallback plugin_init_callbacks[MAX_INIT_CALLBACKS]; diff --git a/editor/surface_upgrade_tool.cpp b/editor/surface_upgrade_tool.cpp index 26ff6e55a03..31834ed0c47 100644 --- a/editor/surface_upgrade_tool.cpp +++ b/editor/surface_upgrade_tool.cpp @@ -32,11 +32,15 @@ #include "editor/editor_file_system.h" #include "editor/editor_node.h" +#include "editor/editor_settings.h" +#include "scene/scene_string_names.h" #include "servers/rendering_server.h" -void SurfaceUpgradeTool::_add_files(EditorFileSystemDirectory *p_dir, HashSet &r_paths, PackedStringArray &r_files) { +SurfaceUpgradeTool *SurfaceUpgradeTool::singleton = nullptr; + +void SurfaceUpgradeTool::_add_files(EditorFileSystemDirectory *p_dir, Vector &r_reimport_paths, Vector &r_resave_paths) { for (int i = 0; i < p_dir->get_subdir_count(); i++) { - _add_files(p_dir->get_subdir(i), r_paths, r_files); + _add_files(p_dir->get_subdir(i), r_reimport_paths, r_resave_paths); } for (int i = 0; i < p_dir->get_file_count(); i++) { @@ -44,47 +48,116 @@ void SurfaceUpgradeTool::_add_files(EditorFileSystemDirectory *p_dir, HashSetget_file_type(i) == "ArrayMesh" || p_dir->get_file_type(i) == "PackedScene") { if (FileAccess::exists(p_dir->get_file_path(i) + ".import")) { - r_files.push_back(p_dir->get_file_path(i)); + r_reimport_paths.append(p_dir->get_file_path(i) + ".import"); } else { - r_paths.insert(p_dir->get_file_path(i)); + r_resave_paths.append(p_dir->get_file_path(i)); } } } } -void SurfaceUpgradeTool::upgrade_all_meshes() { +void SurfaceUpgradeTool::_try_show_popup() { + if (singleton->show_requested || singleton->popped_up) { + return; + } + singleton->show_requested = true; + + RS::get_singleton()->set_warn_on_surface_upgrade(false); + + if (EditorFileSystem::get_singleton()->is_importing()) { + EditorFileSystem::get_singleton()->connect("resources_reimported", callable_mp(singleton, &SurfaceUpgradeTool::_show_popup), CONNECT_ONE_SHOT); + } else if (EditorNode::get_singleton()->is_inside_tree()) { + singleton->_show_popup(); + } + + // EditorNode may not be ready yet. It will call this tool when it is. +} + +void SurfaceUpgradeTool::_show_popup() { + MutexLock lock(mutex); + if (!show_requested || popped_up) { + return; + } + show_requested = false; + popped_up = true; + + bool accepted = EditorNode::immediate_confirmation_dialog(TTR("This project uses meshes with an outdated mesh format from previous Godot versions. The engine needs to update the format in order to use those meshes.\n\nPress 'Restart & Upgrade' to run the surface upgrade tool which will update and re-save all meshes and scenes. This update will restart the editor and may take several minutes. Upgrading will make the meshes incompatible with previous versions of Godot.\n\nPress 'Upgrade Only' to continue opening the scene as normal. The engine will update each mesh in memory, but the update will not be saved. Choosing this option will lead to slower load times every time this project is loaded."), TTR("Restart & Upgrade"), TTR("Upgrade Only"), 500); + if (accepted) { + EditorSettings::get_singleton()->set_project_metadata("surface_upgrade_tool", "run_on_restart", true); + + Vector reimport_paths; + Vector resave_paths; + _add_files(EditorFileSystem::get_singleton()->get_filesystem(), reimport_paths, resave_paths); + + EditorSettings::get_singleton()->set_project_metadata("surface_upgrade_tool", "reimport_paths", reimport_paths); + EditorSettings::get_singleton()->set_project_metadata("surface_upgrade_tool", "resave_paths", resave_paths); + + EditorNode::get_singleton()->restart_editor(); + } else { + RS::get_singleton()->set_warn_on_surface_upgrade(true); + } +} + +// Ensure that the warnings and popups are skipped. +void SurfaceUpgradeTool::begin_upgrade() { + EditorSettings::get_singleton()->set_project_metadata("surface_upgrade_tool", "run_on_restart", false); + RS::get_singleton()->set_surface_upgrade_callback(nullptr); + RS::get_singleton()->set_warn_on_surface_upgrade(false); + popped_up = true; +} + +void SurfaceUpgradeTool::finish_upgrade() { + EditorNode::get_singleton()->trigger_menu_option(EditorNode::FILE_CLOSE_ALL, true); + // Update all meshes here. - HashSet paths; - PackedStringArray files_to_import; - _add_files(EditorFileSystem::get_singleton()->get_filesystem(), paths, files_to_import); + Vector resave_paths = EditorSettings::get_singleton()->get_project_metadata("surface_upgrade_tool", "resave_paths", Vector()); + EditorProgress ep("surface_upgrade_resave", TTR("Upgrading All Meshes in Project"), resave_paths.size()); - EditorProgress ep("Re-saving all scenes and meshes", TTR("Upgrading All Meshes in Project"), paths.size()); - - ep.step(TTR("Re-importing meshes"), 0); - EditorFileSystem::get_singleton()->reimport_files(files_to_import); - - uint32_t step = 1; - for (const String &file : paths) { - Ref res = ResourceLoader::load(file); - ep.step(TTR("Attempting to re-save ") + file, step++); + for (const String &file_path : resave_paths) { + Ref res = ResourceLoader::load(file_path); + ep.step(TTR("Attempting to re-save ") + file_path); if (res.is_valid()) { // Ignore things that fail to load. ResourceSaver::save(res); } } + EditorSettings::get_singleton()->set_project_metadata("surface_upgrade_tool", "resave_paths", Vector()); + + // Remove the imported scenes/meshes from .import so they will be reimported automatically after this. + Vector reimport_paths = EditorSettings::get_singleton()->get_project_metadata("surface_upgrade_tool", "reimport_paths", Vector()); + for (const String &file_path : reimport_paths) { + Ref config; + config.instantiate(); + Error err = config->load(file_path); + if (err != OK) { + ERR_PRINT("Could not open " + file_path + " for upgrade."); + continue; + } + + String remap_path = config->get_value("remap", "path", ""); + if (remap_path.is_empty()) { + continue; + } + + String path = OS::get_singleton()->get_resource_dir() + remap_path.replace_first("res://", "/"); + print_verbose("Moving to trash: " + path); + err = OS::get_singleton()->move_to_trash(path); + if (err != OK) { + EditorNode::get_singleton()->add_io_error(TTR("Cannot remove:") + "\n" + remap_path + "\n"); + } + } + EditorSettings::get_singleton()->set_project_metadata("surface_upgrade_tool", "reimport_paths", Vector()); + + emit_signal(SNAME("upgrade_finished")); } -void SurfaceUpgradeTool::_show_popup() { - RS::get_singleton()->set_surface_upgrade_callback(nullptr); - bool accepted = EditorNode::immediate_confirmation_dialog(TTR("This project uses meshes with an outdated mesh format from previous Godot versions. The engine needs to update the format in order to use those meshes.\n\nPress 'Upgrade & Re-save' to have the engine scan the project folder and automatically update and re-save all meshes and scenes. This update may take a few minutes. Upgrading will make the meshes incompatible with previous versions of Godot.\n\nPress 'Upgrade Only' to continue opening the scene as normal. The engine will update each mesh in memory, but the update will not be saved. Choosing this option will lead to slower load times every time this project is loaded."), TTR("Upgrade & Re-save"), TTR("Upgrade Only"), 500); - if (accepted) { - RS::get_singleton()->set_warn_on_surface_upgrade(false); - upgrade_all_meshes(); - } +void SurfaceUpgradeTool::_bind_methods() { + ADD_SIGNAL(MethodInfo("upgrade_finished")); } SurfaceUpgradeTool::SurfaceUpgradeTool() { - RS::get_singleton()->set_surface_upgrade_callback(_show_popup); + singleton = this; + RS::get_singleton()->set_surface_upgrade_callback(_try_show_popup); } SurfaceUpgradeTool::~SurfaceUpgradeTool() {} diff --git a/editor/surface_upgrade_tool.h b/editor/surface_upgrade_tool.h index fa052200d8c..70e07c58a12 100644 --- a/editor/surface_upgrade_tool.h +++ b/editor/surface_upgrade_tool.h @@ -35,13 +35,31 @@ class EditorFileSystemDirectory; -class SurfaceUpgradeTool { - static void upgrade_all_meshes(); +class SurfaceUpgradeTool : public Object { + GDCLASS(SurfaceUpgradeTool, Object); - static void _show_popup(); - static void _add_files(EditorFileSystemDirectory *p_dir, HashSet &r_paths, PackedStringArray &r_files); + static SurfaceUpgradeTool *singleton; + + bool show_requested = false; + bool popped_up = false; + Mutex mutex; + + static void _try_show_popup(); + void _show_popup(); + void _add_files(EditorFileSystemDirectory *p_dir, Vector &r_reimport_paths, Vector &r_resave_paths); + +protected: + static void _bind_methods(); public: + static SurfaceUpgradeTool *get_singleton() { return singleton; }; + + bool is_show_requested() const { return show_requested; }; + void show_popup() { _show_popup(); } + + void begin_upgrade(); + void finish_upgrade(); + SurfaceUpgradeTool(); ~SurfaceUpgradeTool(); }; diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index eb940cdd56d..78b5656a740 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2076,10 +2076,10 @@ void RenderingServer::fix_surface_compatibility(SurfaceData &p_surface, const St } if (warn_on_surface_upgrade) { - if (p_path.is_empty()) { - WARN_PRINT("A surface uses an old surface format and needs to be upgraded. The upgrade happens automatically at load time every time until the mesh is saved again or re-imported. Once saved (or re-imported), this mesh will be incompatible with earlier versions of Godot."); - } else { - WARN_PRINT("A surface of " + p_path + " uses an old surface format and needs to be upgraded. The upgrade happens automatically at load time every time until the mesh is saved again or re-imported. Once saved (or re-imported), this mesh will be incompatible with earlier versions of Godot."); + WARN_PRINT_ONCE_ED("At least one surface uses an old surface format and needs to be upgraded. The upgrade happens automatically at load time every time until the mesh is saved again or re-imported. Once saved (or re-imported), this mesh will be incompatible with earlier versions of Godot."); + + if (!p_path.is_empty()) { + WARN_PRINT("A surface of " + p_path + " uses an old surface format and needs to be upgraded."); } } #endif