From 72856d633a6be5c596d4a3231acab009828a2efe Mon Sep 17 00:00:00 2001 From: Hilderin <81109165+Hilderin@users.noreply.github.com> Date: Mon, 27 May 2024 16:40:20 -0400 Subject: [PATCH] Fix FileSystem dock won't show any file folders --- core/io/file_access.cpp | 8 +- core/io/resource_importer.cpp | 18 ++ core/io/resource_importer.h | 3 + core/io/resource_loader.cpp | 55 ++-- doc/classes/EditorFileSystem.xml | 12 + editor/editor_file_system.cpp | 419 ++++++++++++++++++------------- editor/editor_file_system.h | 26 +- editor/editor_node.cpp | 10 + editor/filesystem_dock.cpp | 19 +- editor/filesystem_dock.h | 2 + 10 files changed, 358 insertions(+), 214 deletions(-) diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp index 1cf388b33a7..a762e24ff38 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 then 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 fcf4a727ca4..49ba7b03587 100644 --- a/core/io/resource_importer.cpp +++ b/core/io/resource_importer.cpp @@ -362,6 +362,24 @@ Variant ResourceFormatImporter::get_resource_metadata(const String &p_path) cons return pat.metadata; } + +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; +} + void ResourceFormatImporter::get_classes_used(const String &p_path, HashSet *r_classes) { 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..4a38a7fb4ab 100644 --- a/core/io/resource_importer.h +++ b/core/io/resource_importer.h @@ -93,6 +93,9 @@ 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 c3c37aa89d5..7299631fec4 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -957,36 +957,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 then 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/doc/classes/EditorFileSystem.xml b/doc/classes/EditorFileSystem.xml index 08b40c78000..f3129ede650 100644 --- a/doc/classes/EditorFileSystem.xml +++ b/doc/classes/EditorFileSystem.xml @@ -90,6 +90,18 @@ Emitted if at least one resource is reloaded when the filesystem is scanned. + + + + Emitted when a new scan of the project files has started. + + + + + + Emitted when a scan of the project files has ended. + + Emitted when the list of global script classes gets updated. diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 37e00bf0428..035e2dcd654 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -316,8 +316,6 @@ void EditorFileSystem::_scan_filesystem() { EditorProgressBG scan_progress("efs", "ScanFS", 1000); ScanProgress sp; - sp.low = 0; - sp.hi = 1; sp.progress = &scan_progress; new_filesystem = memnew(EditorFileSystemDirectory); @@ -325,7 +323,8 @@ void EditorFileSystem::_scan_filesystem() { Ref d = DirAccess::create(DirAccess::ACCESS_RESOURCES); d->change_dir("res://"); - _scan_new_dir(new_filesystem, d, sp); + + _scan_new_dir(new_filesystem, d, &sp, 1); dep_update_list.clear(); file_cache.clear(); //clear caches, no longer needed @@ -560,15 +559,27 @@ bool EditorFileSystem::_scan_import_support(const Vector &reimports) { return false; } -bool EditorFileSystem::_update_scan_actions() { +bool EditorFileSystem::_update_scan_actions(bool p_show_progress) { sources_changed.clear(); bool fs_changed = false; Vector reimports; Vector reloads; + HashMap import_group_files; + EditorProgress *editor_progress = nullptr; + if (p_show_progress && scan_actions.size() > 0) { + editor_progress = memnew(EditorProgress("_update_scan_actions", TTR("Scanning actions..."), scan_actions.size())); + editor_progress->step("", 0, true); + } + + int idx_action = 0; for (const ItemAction &ia : scan_actions) { + if (editor_progress) { + editor_progress->step(ia.file, idx_action, false); + } + idx_action++; switch (ia.action) { case ItemAction::ACTION_NONE: { } break; @@ -643,10 +654,17 @@ bool EditorFileSystem::_update_scan_actions() { if (_test_for_reimport(full_path, false)) { //must reimport reimports.push_back(full_path); + if (!ia.import_group_file.is_empty()) { + import_group_files[full_path] = ia.import_group_file; + } Vector dependencies = _get_dependencies(full_path); for (const String &dependency_path : dependencies) { if (import_extensions.has(dependency_path.get_extension())) { reimports.push_back(dependency_path); + String import_groupe_file = ResourceFormatImporter::get_singleton()->get_import_group_file(dependency_path); + if (!ia.import_group_file.is_empty()) { + import_group_files[dependency_path] = import_groupe_file; + } } } } else { @@ -676,6 +694,8 @@ bool EditorFileSystem::_update_scan_actions() { } } + memdelete_notnull(editor_progress); + if (_scan_extensions()) { //needs editor restart //extensions also may provide filetypes to be imported, so they must run before importing @@ -694,7 +714,7 @@ bool EditorFileSystem::_update_scan_actions() { return true; } - reimport_files(reimports); + _reimport_files_internal(reimports, &import_group_files); } else { //reimport files will update the uid cache file so if nothing was reimported, update it manually ResourceUID::get_singleton()->update_cache(); @@ -725,10 +745,10 @@ void EditorFileSystem::scan() { } _update_extensions(); - if (!use_threads) { scanning = true; scan_total = 0; + emit_signal(SNAME("scan_started"), true); _scan_filesystem(); if (filesystem) { memdelete(filesystem); @@ -736,7 +756,7 @@ void EditorFileSystem::scan() { //file_type_cache.clear(); filesystem = new_filesystem; new_filesystem = nullptr; - _update_scan_actions(); + _update_scan_actions(true); scanning = false; _update_pending_script_classes(); _update_pending_scene_groups(); @@ -749,28 +769,50 @@ void EditorFileSystem::scan() { Thread::Settings s; scanning = true; scan_total = 0; + emit_signal(SNAME("scan_started"), true); s.priority = Thread::PRIORITY_LOW; thread.start(_thread_func, this, s); - //tree->hide(); - //progress->show(); } } -void EditorFileSystem::ScanProgress::update(int p_current, int p_total) const { - float ratio = low + ((hi - low) / p_total) * p_current; - progress->step(ratio * 1000); - EditorFileSystem::singleton->scan_total = ratio; +void EditorFileSystem::ScanProgress::increment() { + real++; + nb_file_to_scan--; + current = CLAMP(real / estimated, current, 1); + progress->step(current * 1000); + EditorFileSystem::singleton->scan_total = current; } -EditorFileSystem::ScanProgress EditorFileSystem::ScanProgress::get_sub(int p_current, int p_total) const { - ScanProgress sp = *this; - float slice = (sp.hi - sp.low) / p_total; - sp.low += slice * p_current; - sp.hi = slice; - return sp; +void EditorFileSystem::ScanProgress::update_estimated(int p_depth, int p_nb_sub_dirs, int p_nb_files) { + // The algorithm calculates an estimated value for the progress of scanning directories and files. + // It adjusts the estimate based on the number of directories and files discovered so far, + // and ensures the estimated value does not decrease drastically between updates. + float average = 10; + directories_processed++; + if (nb_dir_to_scan > 0) { + nb_dir_to_scan--; + } + nb_dir_to_scan += p_nb_sub_dirs; + nb_file_to_scan += p_nb_files; + + if (directories_processed > 2) { + average = (real + nb_file_to_scan) / directories_processed; + if (average < 10) { + average = 10; + } + } + + float old_estimated = estimated; + estimated = real + nb_file_to_scan + (nb_dir_to_scan * average * p_depth); + if (estimated < old_estimated * 0.95) { + estimated = old_estimated * 0.95; + } + if (estimated <= real + average) { + estimated = real + average; + } } -void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref &da, const ScanProgress &p_progress) { +void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref &da, ScanProgress *p_progress, int p_depth) { List dirs; List files; @@ -810,11 +852,12 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref(); files.sort_custom(); - int total = dirs.size() + files.size(); - int idx = 0; + p_progress->update_estimated(p_depth, dirs.size(), files.size()); + int idx = 0; for (List::Element *E = dirs.front(); E; E = E->next(), idx++) { - if (da->change_dir(E->get()) == OK) { + String name = E->get(); + if (da->change_dir(name) == OK) { String d = da->get_current_dir(); if (d == cd || !d.begins_with(cd)) { @@ -825,38 +868,27 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Refparent = p_dir; efd->name = E->get(); - _scan_new_dir(efd, da, p_progress.get_sub(idx, total)); + _scan_new_dir(efd, da, p_progress, p_depth + 1); - int idx2 = 0; - for (int i = 0; i < p_dir->subdirs.size(); i++) { - if (efd->name.filenocasecmp_to(p_dir->subdirs[i]->name) < 0) { - break; - } - idx2++; - } - if (idx2 == p_dir->subdirs.size()) { - p_dir->subdirs.push_back(efd); - } else { - p_dir->subdirs.insert(idx2, efd); - } + // Folders are already sorted with FileNoCaseComparator. + p_dir->subdirs.push_back(efd); da->change_dir(".."); } } else { ERR_PRINT("Cannot go into subdir '" + E->get() + "'."); } - - p_progress.update(idx, total); } for (List::Element *E = files.front(); E; E = E->next(), idx++) { - String ext = E->get().get_extension().to_lower(); + String name = E->get(); + String ext = name.get_extension().to_lower(); if (!valid_extensions.has(ext)) { continue; //invalid } EditorFileSystemDirectory::FileInfo *fi = memnew(EditorFileSystemDirectory::FileInfo); - fi->file = E->get(); + fi->file = name; String path = cd.path_join(fi->file); @@ -884,14 +916,6 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Refscript_class_extends = fc->script_class_extends; fi->script_class_icon_path = fc->script_class_icon_path; - if (revalidate_import_files && !ResourceFormatImporter::get_singleton()->are_import_settings_valid(path)) { - ItemAction ia; - ia.action = ItemAction::ACTION_FILE_TEST_REIMPORT; - ia.dir = p_dir; - ia.file = E->get(); - scan_actions.push_back(ia); - } - if (fc->type.is_empty()) { fi->type = ResourceLoader::get_resource_type(path); fi->resource_script_class = ResourceLoader::get_resource_script_class(path); @@ -900,15 +924,23 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Refare_import_settings_valid(path)) { + ItemAction ia; + ia.action = ItemAction::ACTION_FILE_TEST_REIMPORT; + ia.dir = p_dir; + ia.file = E->get(); + ia.import_group_file = fi->import_group_file; + scan_actions.push_back(ia); + } + if (fc->uid == ResourceUID::INVALID_ID) { // imported files should always have a UID, so attempt to fetch it. fi->uid = ResourceLoader::get_resource_uid(path); } } 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; @@ -918,6 +950,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Refget(); + ia.import_group_file = fi->import_group_file; scan_actions.push_back(ia); } } else { @@ -968,11 +1001,11 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Reffiles.push_back(fi); - p_progress.update(idx, total); + p_progress->increment(); } } -void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const ScanProgress &p_progress) { +void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, ScanProgress *p_progress) { uint64_t current_mtime = FileAccess::get_modified_time(p_dir->get_path()); bool updated_dir = false; @@ -1028,7 +1061,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const efd->name = f; Ref d = DirAccess::create(DirAccess::ACCESS_RESOURCES); d->change_dir(cd.path_join(f)); - _scan_new_dir(efd, d, p_progress.get_sub(1, 1)); + _scan_new_dir(efd, d, p_progress, 1); ItemAction ia; ia.action = ItemAction::ACTION_DIR_ADD; @@ -1080,6 +1113,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const ia.action = ItemAction::ACTION_FILE_TEST_REIMPORT; ia.dir = p_dir; ia.file = f; + ia.import_group_file = fi->import_group_file; scan_actions.push_back(ia); } @@ -1130,6 +1164,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const ia.action = ItemAction::ACTION_FILE_TEST_REIMPORT; ia.dir = p_dir; ia.file = p_dir->files[i]->file; + ia.import_group_file = p_dir->files[i]->import_group_file; scan_actions.push_back(ia); } } else if (ResourceCache::has(path)) { //test for potential reload @@ -1179,9 +1214,7 @@ void EditorFileSystem::_thread_func_sources(void *_userdata) { EditorProgressBG pr("sources", TTR("ScanSources"), 1000); ScanProgress sp; sp.progress = ≺ - sp.hi = 1; - sp.low = 0; - efs->_scan_fs_changes(efs->filesystem, sp); + efs->_scan_fs_changes(efs->filesystem, &sp); } efs->scanning_changes_done.set(); } @@ -1204,10 +1237,9 @@ void EditorFileSystem::scan_changes() { EditorProgressBG pr("sources", TTR("ScanSources"), 1000); ScanProgress sp; sp.progress = ≺ - sp.hi = 1; - sp.low = 0; scan_total = 0; - _scan_fs_changes(filesystem, sp); + emit_signal(SNAME("scan_started"), false); + _scan_fs_changes(filesystem, &sp); bool changed = _update_scan_actions(); _update_pending_script_classes(); _update_pending_scene_groups(); @@ -1222,6 +1254,7 @@ void EditorFileSystem::scan_changes() { ERR_FAIL_COND(thread_sources.is_started()); set_process(true); scan_total = 0; + emit_signal(SNAME("scan_started"), false); Thread::Settings s; s.priority = Thread::PRIORITY_LOW; thread_sources.start(_thread_func_sources, this, s); @@ -1275,6 +1308,7 @@ void EditorFileSystem::_notification(int p_what) { if (thread_sources.is_started()) { thread_sources.wait_to_finish(); } + emit_signal(SNAME("scan_stopped"), false); bool changed = _update_scan_actions(); _update_pending_script_classes(); _update_pending_scene_groups(); @@ -1295,7 +1329,8 @@ void EditorFileSystem::_notification(int p_what) { filesystem = new_filesystem; new_filesystem = nullptr; thread.wait_to_finish(); - _update_scan_actions(); + emit_signal(SNAME("scan_stopped"), true); + _update_scan_actions(true); _update_pending_script_classes(); _update_pending_scene_groups(); emit_signal(SNAME("filesystem_changed")); @@ -1578,10 +1613,20 @@ String EditorFileSystem::_get_global_script_class(const String &p_type, const St return String(); } -void EditorFileSystem::_update_script_classes() { +void EditorFileSystem::_update_script_classes(bool p_show_progress) { update_script_mutex.lock(); + EditorProgress *ep = nullptr; + if (p_show_progress && update_script_paths.size() > 0) { + ep = memnew(EditorProgress("update_scripts_classes", TTR("(Re)importing Scripts"), update_script_paths.size() * 2)); + ep->step("", 0, true); + } + + int step_count = 0; for (const String &path : update_script_paths) { + if (ep) { + ep->step(TTR("Registering global classes..."), step_count++, false); + } EditorFileSystem::get_singleton()->register_global_class_script(path, path); } @@ -1590,6 +1635,10 @@ void EditorFileSystem::_update_script_classes() { int index = -1; EditorFileSystemDirectory *efd = find_file(path, &index); + if (ep) { + ep->step(TTR("Updating documentation..."), step_count++, false); + } + if (!efd || index < 0) { // The file was removed continue; @@ -1610,6 +1659,8 @@ void EditorFileSystem::_update_script_classes() { } } + memdelete_notnull(ep); + update_script_paths.clear(); update_script_mutex.unlock(); @@ -1626,9 +1677,9 @@ void EditorFileSystem::_update_script_classes() { ResourceSaver::add_custom_savers(); } -void EditorFileSystem::_update_pending_script_classes() { +void EditorFileSystem::_update_pending_script_classes(bool p_show_progress) { if (!update_script_paths.is_empty()) { - _update_script_classes(); + _update_script_classes(p_show_progress); } else { // In case the class cache file was removed somehow, regenerate it. if (!FileAccess::exists(ScriptServer::get_global_class_cache_file_path())) { @@ -1668,7 +1719,7 @@ void EditorFileSystem::_update_scene_groups() { } if (ep) { - ep->step(TTR("Updating Scene Groups..."), step_count++); + ep->step(TTR("Updating Scene Groups..."), step_count++, false); } } @@ -1749,9 +1800,13 @@ void EditorFileSystem::update_files(const Vector &p_script_paths) { fs->files.remove_at(cpos); } - _update_pending_script_classes(); - _update_pending_scene_groups(); - call_deferred(SNAME("emit_signal"), "filesystem_changed"); //update later + // Preventing update of scripts and scene groups while first scan. + // Some ResourceLoader resave files which invoke update_file while loading (ex: ResourceImporterCSVTranslation). + if (!first_scan) { + _update_pending_script_classes(); + _update_pending_scene_groups(); + call_deferred(SNAME("emit_signal"), "filesystem_changed"); // Update later. + } return; } @@ -1822,9 +1877,13 @@ void EditorFileSystem::update_files(const Vector &p_script_paths) { } } - _update_pending_script_classes(); - _update_pending_scene_groups(); - call_deferred(SNAME("emit_signal"), "filesystem_changed"); //update later + // Preventing update of scripts and scene groups while first scan. + // Some ResourceLoader resave files which invoke update_file while loading (ex: ResourceImporterCSVTranslation). + if (!first_scan) { + _update_pending_script_classes(); + _update_pending_scene_groups(); + call_deferred(SNAME("emit_signal"), "filesystem_changed"); // Update later. + } } HashSet EditorFileSystem::get_valid_extensions() const { @@ -2345,132 +2404,152 @@ void EditorFileSystem::_reimport_thread(uint32_t p_index, ImportThreadData *p_im } void EditorFileSystem::reimport_files(const Vector &p_files) { + _reimport_files_internal(p_files, nullptr); +} + +void EditorFileSystem::_reimport_files_internal(const Vector &p_files, const HashMap *p_import_group_files) { ERR_FAIL_COND_MSG(importing, "Attempted to call reimport_files() recursively, this is not allowed."); importing = true; Vector reloads; - EditorProgress pr("reimport", TTR("(Re)Importing Assets"), p_files.size()); + { + EditorProgress pr("reimport", TTR("(Re)Importing Assets"), p_files.size()); + pr.step("", 0, true); - Vector reimport_files; + Vector reimport_files; + HashMap import_group_files = *p_import_group_files; - HashSet groups_to_reimport; + HashSet groups_to_reimport; - for (int i = 0; i < p_files.size(); i++) { - String file = p_files[i]; + for (int i = 0; i < p_files.size(); i++) { + String file = p_files[i]; - ResourceUID::ID uid = ResourceUID::get_singleton()->text_to_id(file); - if (uid != ResourceUID::INVALID_ID && ResourceUID::get_singleton()->has_id(uid)) { - file = ResourceUID::get_singleton()->get_id_path(uid); + ResourceUID::ID uid = ResourceUID::get_singleton()->text_to_id(file); + if (uid != ResourceUID::INVALID_ID && ResourceUID::get_singleton()->has_id(uid)) { + file = ResourceUID::get_singleton()->get_id_path(uid); + } + + String group_file; + if (p_import_group_files) { + if (p_import_group_files->has(file)) { + group_file = (*p_import_group_files)[file]; + } + } else { + group_file = ResourceFormatImporter::get_singleton()->get_import_group_file(file); + } + + if (group_file_cache.has(file)) { + // Maybe the file itself is a group! + groups_to_reimport.insert(file); + // Groups do not belong to groups. + group_file = String(); + } else if (groups_to_reimport.has(file)) { + // Groups do not belong to groups. + group_file = String(); + } else if (!group_file.is_empty()) { + // It's a group file, add group to import and skip this file. + groups_to_reimport.insert(group_file); + } else { + // It's a regular file. + ImportFile ifile; + ifile.path = file; + ResourceFormatImporter::get_singleton()->get_import_order_threads_and_importer(file, ifile.order, ifile.threaded, ifile.importer); + reloads.push_back(file); + reimport_files.push_back(ifile); + } + + // Group may have changed, so also update group reference. + if (!p_import_group_files) { + EditorFileSystemDirectory *fs = nullptr; + int cpos = -1; + if (_find_file(file, &fs, cpos)) { + fs->files.write[cpos]->import_group_file = group_file; + } + } + + pr.step(TTR("Preparing files to reimport..."), i, false); } - String group_file = ResourceFormatImporter::get_singleton()->get_import_group_file(file); - - if (group_file_cache.has(file)) { - // Maybe the file itself is a group! - groups_to_reimport.insert(file); - // Groups do not belong to groups. - group_file = String(); - } else if (groups_to_reimport.has(file)) { - // Groups do not belong to groups. - group_file = String(); - } else if (!group_file.is_empty()) { - // It's a group file, add group to import and skip this file. - groups_to_reimport.insert(group_file); - } else { - // It's a regular file. - ImportFile ifile; - ifile.path = file; - ResourceFormatImporter::get_singleton()->get_import_order_threads_and_importer(file, ifile.order, ifile.threaded, ifile.importer); - reloads.push_back(file); - reimport_files.push_back(ifile); - } - - // Group may have changed, so also update group reference. - EditorFileSystemDirectory *fs = nullptr; - int cpos = -1; - if (_find_file(file, &fs, cpos)) { - fs->files.write[cpos]->import_group_file = group_file; - } - } - - reimport_files.sort(); + reimport_files.sort(); #ifdef THREADS_ENABLED - bool use_multiple_threads = GLOBAL_GET("editor/import/use_multiple_threads"); + bool use_multiple_threads = GLOBAL_GET("editor/import/use_multiple_threads"); #else - bool use_multiple_threads = false; + bool use_multiple_threads = false; #endif - int from = 0; - for (int i = 0; i < reimport_files.size(); i++) { - if (groups_to_reimport.has(reimport_files[i].path)) { - continue; - } + int from = 0; + for (int i = 0; i < reimport_files.size(); i++) { + if (groups_to_reimport.has(reimport_files[i].path)) { + continue; + } - if (use_multiple_threads && reimport_files[i].threaded) { - if (i + 1 == reimport_files.size() || reimport_files[i + 1].importer != reimport_files[from].importer) { - if (from - i == 0) { - // Single file, do not use threads. - pr.step(reimport_files[i].path.get_file(), i); - _reimport_file(reimport_files[i].path); - } else { - Ref importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(reimport_files[from].importer); - ERR_CONTINUE(!importer.is_valid()); + if (use_multiple_threads && reimport_files[i].threaded) { + if (i + 1 == reimport_files.size() || reimport_files[i + 1].importer != reimport_files[from].importer) { + if (from - i == 0) { + // Single file, do not use threads. + pr.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); + ERR_CONTINUE(importer.is_null()); - importer->import_threaded_begin(); + importer->import_threaded_begin(); - ImportThreadData tdata; - tdata.max_index.set(from); - tdata.reimport_from = from; - tdata.reimport_files = reimport_files.ptr(); + ImportThreadData tdata; + tdata.max_index.set(from); + tdata.reimport_from = from; + tdata.reimport_files = reimport_files.ptr(); - WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &EditorFileSystem::_reimport_thread, &tdata, i - from + 1, -1, false, vformat(TTR("Import resources of type: %s"), reimport_files[from].importer)); - int current_index = from - 1; - 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); - } - OS::get_singleton()->delay_usec(1); - } while (!WorkerThreadPool::get_singleton()->is_group_task_completed(group_task)); + WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &EditorFileSystem::_reimport_thread, &tdata, i - from + 1, -1, false, vformat(TTR("Import resources of type: %s"), reimport_files[from].importer)); + int current_index = from - 1; + 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, false); + } + OS::get_singleton()->delay_usec(1); + } while (!WorkerThreadPool::get_singleton()->is_group_task_completed(group_task)); - WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task); + WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task); - importer->import_threaded_end(); + importer->import_threaded_end(); + } + + from = i + 1; } - from = i + 1; - } - - } else { - pr.step(reimport_files[i].path.get_file(), i); - _reimport_file(reimport_files[i].path); - } - } - - // Reimport groups. - - from = reimport_files.size(); - - if (groups_to_reimport.size()) { - 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++); - Error err = _reimport_group(E.key, E.value); - reloads.push_back(E.key); - reloads.append_array(E.value); - if (err == OK) { - _reimport_file(E.key); + } else { + pr.step(reimport_files[i].path.get_file(), i, false); + _reimport_file(reimport_files[i].path); } } + + // Reimport groups. + + from = reimport_files.size(); + + if (groups_to_reimport.size()) { + 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++, false); + Error err = _reimport_group(E.key, E.value); + reloads.push_back(E.key); + reloads.append_array(E.value); + if (err == OK) { + _reimport_file(E.key); + } + } + } + + ResourceUID::get_singleton()->update_cache(); // After reimporting, update the cache. + + _save_filesystem_cache(); } - ResourceUID::get_singleton()->update_cache(); // After reimporting, update the cache. - - _save_filesystem_cache(); - _update_pending_script_classes(); + _update_pending_script_classes(true); _update_pending_scene_groups(); importing = false; if (!is_scanning()) { @@ -2688,6 +2767,8 @@ void EditorFileSystem::_bind_methods() { ADD_SIGNAL(MethodInfo("sources_changed", PropertyInfo(Variant::BOOL, "exist"))); ADD_SIGNAL(MethodInfo("resources_reimported", PropertyInfo(Variant::PACKED_STRING_ARRAY, "resources"))); ADD_SIGNAL(MethodInfo("resources_reload", PropertyInfo(Variant::PACKED_STRING_ARRAY, "resources"))); + ADD_SIGNAL(MethodInfo("scan_started", PropertyInfo(Variant::BOOL, "complete_scan"))); + ADD_SIGNAL(MethodInfo("scan_stopped", PropertyInfo(Variant::BOOL, "complete_scan"))); } void EditorFileSystem::_update_extensions() { diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h index cd95d5fb951..ea839ec823d 100644 --- a/editor/editor_file_system.h +++ b/editor/editor_file_system.h @@ -153,6 +153,7 @@ class EditorFileSystem : public Node { Action action = ACTION_NONE; EditorFileSystemDirectory *dir = nullptr; String file; + String import_group_file; EditorFileSystemDirectory *new_dir = nullptr; EditorFileSystemDirectory::FileInfo *new_file = nullptr; }; @@ -200,11 +201,15 @@ class EditorFileSystem : public Node { HashSet dep_update_list; struct ScanProgress { - float low = 0; - float hi = 0; - mutable EditorProgressBG *progress = nullptr; - void update(int p_current, int p_total) const; - ScanProgress get_sub(int p_current, int p_total) const; + int directories_processed = 0; + int nb_dir_to_scan = 0; + int nb_file_to_scan = 0; + float estimated = 0; + float real = 0; + float current = 0; + EditorProgressBG *progress = nullptr; + void increment(); + void update_estimated(int p_depth, int p_nb_dirs, int p_nb_files); }; void _save_filesystem_cache(); @@ -212,7 +217,7 @@ class EditorFileSystem : public Node { bool _find_file(const String &p_file, EditorFileSystemDirectory **r_d, int &r_file_pos) const; - void _scan_fs_changes(EditorFileSystemDirectory *p_dir, const ScanProgress &p_progress); + void _scan_fs_changes(EditorFileSystemDirectory *p_dir, ScanProgress *p_progress); void _delete_internal_files(const String &p_file); @@ -220,7 +225,7 @@ class EditorFileSystem : public Node { HashSet valid_extensions; HashSet import_extensions; - void _scan_new_dir(EditorFileSystemDirectory *p_dir, Ref &da, const ScanProgress &p_progress); + void _scan_new_dir(EditorFileSystemDirectory *p_dir, Ref &da, ScanProgress *p_progress, int p_depth); Thread thread_sources; bool scanning_changes = false; @@ -231,7 +236,7 @@ class EditorFileSystem : public Node { List sources_changed; List scan_actions; - bool _update_scan_actions(); + bool _update_scan_actions(bool p_show_progress = false); void _update_extensions(); @@ -257,8 +262,8 @@ class EditorFileSystem : public Node { Mutex update_script_mutex; HashSet update_script_paths; void _queue_update_script_class(const String &p_path); - void _update_script_classes(); - void _update_pending_script_classes(); + void _update_script_classes(bool p_show_progress = false); + void _update_pending_script_classes(bool p_show_progress = false); Mutex update_scene_mutex; HashSet update_scene_paths; @@ -286,6 +291,7 @@ class EditorFileSystem : public Node { SafeNumeric max_index; }; + void _reimport_files_internal(const Vector &p_files, const HashMap *p_import_group_files); void _reimport_thread(uint32_t p_index, ImportThreadData *p_import_data); static ResourceUID::ID _resource_saver_get_resource_id_for_path(const String &p_path, bool p_generate); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 94bd590fc19..b58b3784145 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -5103,6 +5103,8 @@ void EditorNode::save_editor_layout_delayed() { } void EditorNode::_load_editor_layout() { + EditorProgress ep("loading_editor_layout", TTR("Loading editor"), 5); + ep.step("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")); @@ -5124,11 +5126,19 @@ void EditorNode::_load_editor_layout() { return; } + ep.step("Loading docks...", 1, true); editor_dock_manager->load_docks_from_config(config, "docks"); + + ep.step("Reopening scenes...", 2, true); _load_open_scenes_from_config(config); + + ep.step("Loading central editor layout...", 3, true); _load_central_editor_layout_from_config(config); + ep.step("Loading plugin window layout...", 4, true); editor_data.set_plugin_window_layout(config); + + ep.step("Editor layout ready.", 5, true); } void EditorNode::_save_central_editor_layout_to_config(Ref p_config_file) { diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index f8a82187b9d..7d90da05c26 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -550,6 +550,8 @@ void FileSystemDock::_notification(int p_what) { case NOTIFICATION_READY: { EditorFeatureProfileManager::get_singleton()->connect("current_feature_profile_changed", callable_mp(this, &FileSystemDock::_feature_profile_changed)); EditorFileSystem::get_singleton()->connect("filesystem_changed", callable_mp(this, &FileSystemDock::_fs_changed)); + EditorFileSystem::get_singleton()->connect("scan_started", callable_mp(this, &FileSystemDock::_scan_started)); + EditorFileSystem::get_singleton()->connect("scan_stopped", callable_mp(this, &FileSystemDock::_scan_stopped)); EditorResourcePreview::get_singleton()->connect("preview_invalidated", callable_mp(this, &FileSystemDock::_preview_invalidated)); button_file_list_display_mode->connect(SceneStringName(pressed), callable_mp(this, &FileSystemDock::_toggle_file_display)); @@ -566,9 +568,7 @@ void FileSystemDock::_notification(int p_what) { _update_display_mode(); - if (EditorFileSystem::get_singleton()->is_scanning()) { - _set_scanning_mode(); - } else { + if (!EditorFileSystem::get_singleton()->is_scanning()) { _update_tree(Vector(), true); } } break; @@ -1326,6 +1326,18 @@ void FileSystemDock::_fs_changed() { set_process(false); } +void FileSystemDock::_scan_started(bool p_complete_scan) { + if (p_complete_scan) { + _set_scanning_mode(); + } +} + +void FileSystemDock::_scan_stopped(bool p_complete_scan) { + if (p_complete_scan) { + _fs_changed(); + } +} + void FileSystemDock::_set_scanning_mode() { button_hist_prev->set_disabled(true); button_hist_next->set_disabled(true); @@ -2649,7 +2661,6 @@ bool FileSystemDock::_matches_all_search_tokens(const String &p_text) { } void FileSystemDock::_rescan() { - _set_scanning_mode(); EditorFileSystem::get_singleton()->scan(); } diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index 3fbff3ef194..2e9e52fcf6e 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -308,6 +308,8 @@ private: void _set_scanning_mode(); void _rescan(); + void _scan_started(bool p_complete_scan); + void _scan_stopped(bool p_complete_scan); void _change_split_mode(); void _split_dragged(int p_offset);