diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp index 1cf388b33a7..c857d549251 100644 --- a/core/io/file_access.cpp +++ b/core/io/file_access.cpp @@ -59,11 +59,9 @@ bool FileAccess::exists(const String &p_name) { return true; } - Ref f = open(p_name, READ); - if (f.is_null()) { - return false; - } - return true; + // Using file_exists because it's faster than trying to open the file. + Ref ret = create_for_path(p_name); + return ret->file_exists(p_name); } void FileAccess::_set_access_type(AccessType p_access) { diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp index 9e6f3ba3142..b4c43abe002 100644 --- a/core/io/resource_importer.cpp +++ b/core/io/resource_importer.cpp @@ -364,6 +364,23 @@ ResourceUID::ID ResourceFormatImporter::get_resource_uid(const String &p_path) c return pat.uid; } +Error ResourceFormatImporter::get_resource_import_info(const String &p_path, StringName &r_type, ResourceUID::ID &r_uid, String &r_import_group_file) const { + PathAndType pat; + Error err = _get_path_and_type(p_path, pat); + + if (err == OK) { + r_type = pat.type; + r_uid = pat.uid; + r_import_group_file = pat.group_file; + } else { + r_type = ""; + r_uid = ResourceUID::INVALID_ID; + r_import_group_file = ""; + } + + return err; +} + Variant ResourceFormatImporter::get_resource_metadata(const String &p_path) const { PathAndType pat; Error err = _get_path_and_type(p_path, pat); diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h index dbd9e70d16b..7b1806c3d2a 100644 --- a/core/io/resource_importer.h +++ b/core/io/resource_importer.h @@ -93,6 +93,7 @@ public: String get_import_settings_hash() const; String get_import_base_path(const String &p_for_file) const; + Error get_resource_import_info(const String &p_path, StringName &r_type, ResourceUID::ID &r_uid, String &r_import_group_file) const; ResourceFormatImporter(); }; diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index eaee849a876..fc16527196c 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -1104,36 +1104,39 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem new_path = path_remaps[new_path]; } else { // Try file remap. - Error err; - Ref f = FileAccess::open(new_path + ".remap", FileAccess::READ, &err); - if (f.is_valid()) { - VariantParser::StreamFile stream; - stream.f = f; + // Usually, there's no remap file and FileAccess::exists() is faster than FileAccess::open(). + if (FileAccess::exists(new_path + ".remap")) { + Error err; + Ref f = FileAccess::open(new_path + ".remap", FileAccess::READ, &err); + if (f.is_valid()) { + VariantParser::StreamFile stream; + stream.f = f; - String assign; - Variant value; - VariantParser::Tag next_tag; + String assign; + Variant value; + VariantParser::Tag next_tag; - int lines = 0; - String error_text; - while (true) { - assign = Variant(); - next_tag.fields.clear(); - next_tag.name = String(); + int lines = 0; + String error_text; + while (true) { + assign = Variant(); + next_tag.fields.clear(); + next_tag.name = String(); - err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, nullptr, true); - if (err == ERR_FILE_EOF) { - break; - } else if (err != OK) { - ERR_PRINT("Parse error: " + p_path + ".remap:" + itos(lines) + " error: " + error_text + "."); - break; - } + err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, nullptr, true); + if (err == ERR_FILE_EOF) { + break; + } else if (err != OK) { + ERR_PRINT("Parse error: " + p_path + ".remap:" + itos(lines) + " error: " + error_text + "."); + break; + } - if (assign == "path") { - new_path = value; - break; - } else if (next_tag.name != "remap") { - break; + if (assign == "path") { + new_path = value; + break; + } else if (next_tag.name != "remap") { + break; + } } } } diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 4d5749d9495..22ff7a4509b 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -228,15 +228,18 @@ EditorFileSystem::ScannedDirectory::~ScannedDirectory() { } void EditorFileSystem::_first_scan_filesystem() { + EditorProgress ep = EditorProgress("first_scan_filesystem", TTR("Project initialization"), 5); Ref d = DirAccess::create(DirAccess::ACCESS_RESOURCES); first_scan_root_dir = memnew(ScannedDirectory); first_scan_root_dir->full_path = "res://"; HashSet existing_class_names; + ep.step(TTR("Scanning file structure..."), 0, true); nb_files_total = _scan_new_dir(first_scan_root_dir, d); // This loads the global class names from the scripts and ensures that even if the // global_script_class_cache.cfg was missing or invalid, the global class names are valid in ScriptServer. + ep.step(TTR("Loading global class names..."), 1, true); _first_scan_process_scripts(first_scan_root_dir, existing_class_names); // Removing invalid global class to prevent having invalid paths in ScriptServer. @@ -245,8 +248,13 @@ void EditorFileSystem::_first_scan_filesystem() { // Now that all the global class names should be loaded, create autoloads and plugins. // This is done after loading the global class names because autoloads and plugins can use // global class names. + ep.step(TTR("Creating autoload scripts..."), 3, true); ProjectSettingsEditor::get_singleton()->init_autoloads(); + + ep.step(TTR("Initializing plugins..."), 4, true); EditorNode::get_singleton()->init_plugins(); + + ep.step(TTR("Starting file scan..."), 5, true); } void EditorFileSystem::_first_scan_process_scripts(const ScannedDirectory *p_scan_dir, HashSet &p_existing_class_names) { @@ -650,6 +658,12 @@ bool EditorFileSystem::_update_scan_actions() { Vector reimports; Vector reloads; + EditorProgress *ep = nullptr; + if (scan_actions.size() > 1) { + ep = memnew(EditorProgress("_update_scan_actions", TTR("Scanning actions..."), scan_actions.size())); + } + + int step_count = 0; for (const ItemAction &ia : scan_actions) { switch (ia.action) { case ItemAction::ACTION_NONE: { @@ -781,8 +795,14 @@ bool EditorFileSystem::_update_scan_actions() { } break; } + + if (ep) { + ep->step(ia.file, step_count++, false); + } } + memdelete_notnull(ep); + if (_scan_extensions()) { //needs editor restart //extensions also may provide filetypes to be imported, so they must run before importing @@ -872,8 +892,6 @@ void EditorFileSystem::scan() { scan_total = 0; s.priority = Thread::PRIORITY_LOW; thread.start(_thread_func, this, s); - //tree->hide(); - //progress->show(); } } @@ -1022,9 +1040,8 @@ void EditorFileSystem::_process_file_system(const ScannedDirectory *p_scan_dir, } } else { - fi->type = ResourceFormatImporter::get_singleton()->get_resource_type(path); - fi->uid = ResourceFormatImporter::get_singleton()->get_resource_uid(path); - fi->import_group_file = ResourceFormatImporter::get_singleton()->get_import_group_file(path); + // Using get_resource_import_info() to prevent calling 3 times ResourceFormatImporter::_get_path_and_type. + ResourceFormatImporter::get_singleton()->get_resource_import_info(path, fi->type, fi->uid, fi->import_group_file); fi->script_class_name = _get_global_script_class(fi->type, path, &fi->script_class_extends, &fi->script_class_icon_path); fi->modified_time = 0; fi->import_modified_time = 0; @@ -1830,10 +1847,21 @@ void EditorFileSystem::_update_script_classes() { update_script_mutex.lock(); + EditorProgress *ep = nullptr; + if (update_script_paths.size() > 1) { + ep = memnew(EditorProgress("update_scripts_classes", TTR("Registering global classes..."), update_script_paths.size())); + } + + int step_count = 0; for (const KeyValue &E : update_script_paths) { _register_global_class_script(E.key, E.key, E.value.type, E.value.script_class_name, E.value.script_class_extends, E.value.script_class_icon_path); + if (ep) { + ep->step(E.value.script_class_name, step_count++, false); + } } + memdelete_notnull(ep); + update_script_paths.clear(); update_script_mutex.unlock(); @@ -1858,6 +1886,12 @@ void EditorFileSystem::_update_script_documentation() { update_script_mutex.lock(); + EditorProgress *ep = nullptr; + if (update_script_paths_documentation.size() > 1) { + ep = memnew(EditorProgress("update_script_paths_documentation", TTR("Updating scripts documentation"), update_script_paths_documentation.size())); + } + + int step_count = 0; for (const String &path : update_script_paths_documentation) { int index = -1; EditorFileSystemDirectory *efd = find_file(path, &index); @@ -1880,8 +1914,14 @@ void EditorFileSystem::_update_script_documentation() { } } } + + if (ep) { + ep->step(efd->files[index]->file, step_count++, false); + } } + memdelete_notnull(ep); + update_script_paths_documentation.clear(); update_script_mutex.unlock(); } @@ -1916,7 +1956,7 @@ void EditorFileSystem::_update_scene_groups() { EditorProgress *ep = nullptr; if (update_scene_paths.size() > 20) { - ep = memnew(EditorProgress("update_scene_groups", TTR("Update Scene Groups"), update_scene_paths.size())); + ep = memnew(EditorProgress("update_scene_groups", TTR("Updating Scene Groups"), update_scene_paths.size())); } int step_count = 0; @@ -1938,7 +1978,7 @@ void EditorFileSystem::_update_scene_groups() { } if (ep) { - ep->step(TTR("Updating Scene Groups..."), step_count++); + ep->step(efd->files[index]->file, step_count++); } } @@ -2654,13 +2694,15 @@ void EditorFileSystem::reimport_files(const Vector &p_files) { Vector reloads; - EditorProgress pr("reimport", TTR("(Re)Importing Assets"), p_files.size()); + EditorProgress *ep = memnew(EditorProgress("reimport", TTR("(Re)Importing Assets"), p_files.size())); Vector reimport_files; HashSet groups_to_reimport; for (int i = 0; i < p_files.size(); i++) { + ep->step(TTR("Preparing files to reimport..."), i, false); + String file = p_files[i]; ResourceUID::ID uid = ResourceUID::get_singleton()->text_to_id(file); @@ -2700,6 +2742,8 @@ void EditorFileSystem::reimport_files(const Vector &p_files) { reimport_files.sort(); + ep->step(TTR("Executing pre-reimport operations..."), 0, true); + // Emit the resource_reimporting signal for the single file before the actual importation. emit_signal(SNAME("resources_reimporting"), reloads); @@ -2720,7 +2764,7 @@ void EditorFileSystem::reimport_files(const Vector &p_files) { if (i + 1 == reimport_files.size() || reimport_files[i + 1].importer != reimport_files[from].importer || groups_to_reimport.has(reimport_files[i + 1].path)) { if (from - i == 0) { // Single file, do not use threads. - pr.step(reimport_files[i].path.get_file(), i); + ep->step(reimport_files[i].path.get_file(), i, false); _reimport_file(reimport_files[i].path); } else { Ref importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(reimport_files[from].importer); @@ -2742,7 +2786,7 @@ void EditorFileSystem::reimport_files(const Vector &p_files) { do { if (current_index < tdata.max_index.get()) { current_index = tdata.max_index.get(); - pr.step(reimport_files[current_index].path.get_file(), current_index); + ep->step(reimport_files[current_index].path.get_file(), current_index, false); } OS::get_singleton()->delay_usec(1); } while (!WorkerThreadPool::get_singleton()->is_group_task_completed(group_task)); @@ -2756,7 +2800,7 @@ void EditorFileSystem::reimport_files(const Vector &p_files) { } } else { - pr.step(reimport_files[i].path.get_file(), i); + ep->step(reimport_files[i].path.get_file(), i, false); _reimport_file(reimport_files[i].path); // We need to increment the counter, maybe the next file is multithreaded @@ -2773,7 +2817,7 @@ void EditorFileSystem::reimport_files(const Vector &p_files) { HashMap> group_files; _find_group_files(filesystem, group_files, groups_to_reimport); for (const KeyValue> &E : group_files) { - pr.step(E.key.get_file(), from++); + ep->step(E.key.get_file(), from++, false); Error err = _reimport_group(E.key, E.value); reloads.push_back(E.key); reloads.append_array(E.value); @@ -2784,15 +2828,20 @@ void EditorFileSystem::reimport_files(const Vector &p_files) { } ResourceUID::get_singleton()->update_cache(); // After reimporting, update the cache. - _save_filesystem_cache(); + + memdelete_notnull(ep); + _process_update_pending(); importing = false; + + ep = memnew(EditorProgress("reimport", TTR("(Re)Importing Assets"), p_files.size())); + ep->step(TTR("Executing post-reimport operations..."), 0, true); if (!is_scanning()) { emit_signal(SNAME("filesystem_changed")); } - emit_signal(SNAME("resources_reimported"), reloads); + memdelete_notnull(ep); } Error EditorFileSystem::reimport_append(const String &p_file, const HashMap &p_custom_options, const String &p_custom_importer, Variant p_generator_parameters) { diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index a8f8edaae88..80cd4c64e4c 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -1073,30 +1073,32 @@ void EditorNode::_resources_reimporting(const Vector &p_resources) { // the inherited scene. Then, get_modified_properties_for_node will return the mesh property, // which will trigger a recopy of the previous mesh, preventing the reload. scenes_modification_table.clear(); - List scenes; + scenes_reimported.clear(); + resources_reimported.clear(); + EditorFileSystem *editor_file_system = EditorFileSystem::get_singleton(); for (const String &res_path : p_resources) { - if (ResourceLoader::get_resource_type(res_path) == "PackedScene") { - scenes.push_back(res_path); + // It's faster to use EditorFileSystem::get_file_type than fetching the resource type from disk. + // This makes a big difference when reimporting many resources. + String file_type = editor_file_system->get_file_type(res_path); + if (file_type.is_empty()) { + file_type = ResourceLoader::get_resource_type(res_path); + } + if (file_type == "PackedScene") { + scenes_reimported.push_back(res_path); + } else { + resources_reimported.push_back(res_path); } } - if (scenes.size() > 0) { - preload_reimporting_with_path_in_edited_scenes(scenes); + if (scenes_reimported.size() > 0) { + preload_reimporting_with_path_in_edited_scenes(scenes_reimported); } } void EditorNode::_resources_reimported(const Vector &p_resources) { - List scenes; int current_tab = scene_tabs->get_current_tab(); - for (const String &res_path : p_resources) { - String file_type = ResourceLoader::get_resource_type(res_path); - if (file_type == "PackedScene") { - scenes.push_back(res_path); - // Reload later if needed, first go with normal resources. - continue; - } - + for (const String &res_path : resources_reimported) { if (!ResourceCache::has(res_path)) { // Not loaded, no need to reload. continue; @@ -1110,16 +1112,20 @@ void EditorNode::_resources_reimported(const Vector &p_resources) { // Editor may crash when related animation is playing while re-importing GLTF scene, stop it in advance. AnimationPlayer *ap = AnimationPlayerEditor::get_singleton()->get_player(); - if (ap && scenes.size() > 0) { + if (ap && scenes_reimported.size() > 0) { ap->stop(true); } - for (const String &E : scenes) { + for (const String &E : scenes_reimported) { reload_scene(E); } reload_instances_with_path_in_edited_scenes(); + scenes_modification_table.clear(); + scenes_reimported.clear(); + resources_reimported.clear(); + _set_current_scene_nocheck(current_tab); } @@ -5239,6 +5245,8 @@ void EditorNode::save_editor_layout_delayed() { } void EditorNode::_load_editor_layout() { + EditorProgress ep("loading_editor_layout", TTR("Loading editor"), 5); + ep.step(TTR("Loading editor layout..."), 0, true); Ref config; config.instantiate(); Error err = config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg")); @@ -5260,11 +5268,19 @@ void EditorNode::_load_editor_layout() { return; } + ep.step(TTR("Loading docks..."), 1, true); editor_dock_manager->load_docks_from_config(config, "docks"); + + ep.step(TTR("Reopening scenes..."), 2, true); _load_open_scenes_from_config(config); + + ep.step(TTR("Loading central editor layout..."), 3, true); _load_central_editor_layout_from_config(config); + ep.step(TTR("Loading plugin window layout..."), 4, true); editor_data.set_plugin_window_layout(config); + + ep.step(TTR("Editor layout ready."), 5, true); } void EditorNode::_save_central_editor_layout_to_config(Ref p_config_file) { @@ -6328,8 +6344,6 @@ void EditorNode::reload_instances_with_path_in_edited_scenes() { editor_data.restore_edited_scene_state(editor_selection, &editor_history); - scenes_modification_table.clear(); - progress.step(TTR("Reloading done."), editor_data.get_edited_scene_count()); } diff --git a/editor/editor_node.h b/editor/editor_node.h index 222b1cf90c7..0eac64c9c3a 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -845,6 +845,8 @@ public: }; HashMap scenes_modification_table; + List scenes_reimported; + List resources_reimported; void update_node_from_node_modification_entry(Node *p_node, ModificationNodeEntry &p_node_modification);