Fix FileSystem dock won't show any file folders

This commit is contained in:
Hilderin 2024-05-27 16:40:20 -04:00
parent 5241d30bfa
commit 72856d633a
10 changed files with 358 additions and 214 deletions

View file

@ -59,11 +59,9 @@ bool FileAccess::exists(const String &p_name) {
return true; return true;
} }
Ref<FileAccess> f = open(p_name, READ); // Using file_exists because it's faster then trying to open the file.
if (f.is_null()) { Ref<FileAccess> ret = create_for_path(p_name);
return false; return ret->file_exists(p_name);
}
return true;
} }
void FileAccess::_set_access_type(AccessType p_access) { void FileAccess::_set_access_type(AccessType p_access) {

View file

@ -362,6 +362,24 @@ Variant ResourceFormatImporter::get_resource_metadata(const String &p_path) cons
return pat.metadata; 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<StringName> *r_classes) { void ResourceFormatImporter::get_classes_used(const String &p_path, HashSet<StringName> *r_classes) {
PathAndType pat; PathAndType pat;
Error err = _get_path_and_type(p_path, pat); Error err = _get_path_and_type(p_path, pat);

View file

@ -93,6 +93,9 @@ public:
String get_import_settings_hash() const; String get_import_settings_hash() const;
String get_import_base_path(const String &p_for_file) 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(); ResourceFormatImporter();
}; };

View file

@ -957,36 +957,39 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem
new_path = path_remaps[new_path]; new_path = path_remaps[new_path];
} else { } else {
// Try file remap. // Try file remap.
Error err; // Usually, there's no remap file and FileAccess::exists() is faster then FileAccess::open().
Ref<FileAccess> f = FileAccess::open(new_path + ".remap", FileAccess::READ, &err); if (FileAccess::exists(new_path + ".remap")) {
if (f.is_valid()) { Error err;
VariantParser::StreamFile stream; Ref<FileAccess> f = FileAccess::open(new_path + ".remap", FileAccess::READ, &err);
stream.f = f; if (f.is_valid()) {
VariantParser::StreamFile stream;
stream.f = f;
String assign; String assign;
Variant value; Variant value;
VariantParser::Tag next_tag; VariantParser::Tag next_tag;
int lines = 0; int lines = 0;
String error_text; String error_text;
while (true) { while (true) {
assign = Variant(); assign = Variant();
next_tag.fields.clear(); next_tag.fields.clear();
next_tag.name = String(); next_tag.name = String();
err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, nullptr, true); err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, nullptr, true);
if (err == ERR_FILE_EOF) { if (err == ERR_FILE_EOF) {
break; break;
} else if (err != OK) { } else if (err != OK) {
ERR_PRINT("Parse error: " + p_path + ".remap:" + itos(lines) + " error: " + error_text + "."); ERR_PRINT("Parse error: " + p_path + ".remap:" + itos(lines) + " error: " + error_text + ".");
break; break;
} }
if (assign == "path") { if (assign == "path") {
new_path = value; new_path = value;
break; break;
} else if (next_tag.name != "remap") { } else if (next_tag.name != "remap") {
break; break;
}
} }
} }
} }

View file

@ -90,6 +90,18 @@
Emitted if at least one resource is reloaded when the filesystem is scanned. Emitted if at least one resource is reloaded when the filesystem is scanned.
</description> </description>
</signal> </signal>
<signal name="scan_started">
<param index="0" name="complete_scan" type="bool" />
<description>
Emitted when a new scan of the project files has started.
</description>
</signal>
<signal name="scan_stopped">
<param index="0" name="complete_scan" type="bool" />
<description>
Emitted when a scan of the project files has ended.
</description>
</signal>
<signal name="script_classes_updated"> <signal name="script_classes_updated">
<description> <description>
Emitted when the list of global script classes gets updated. Emitted when the list of global script classes gets updated.

View file

@ -316,8 +316,6 @@ void EditorFileSystem::_scan_filesystem() {
EditorProgressBG scan_progress("efs", "ScanFS", 1000); EditorProgressBG scan_progress("efs", "ScanFS", 1000);
ScanProgress sp; ScanProgress sp;
sp.low = 0;
sp.hi = 1;
sp.progress = &scan_progress; sp.progress = &scan_progress;
new_filesystem = memnew(EditorFileSystemDirectory); new_filesystem = memnew(EditorFileSystemDirectory);
@ -325,7 +323,8 @@ void EditorFileSystem::_scan_filesystem() {
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES); Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
d->change_dir("res://"); d->change_dir("res://");
_scan_new_dir(new_filesystem, d, sp);
_scan_new_dir(new_filesystem, d, &sp, 1);
dep_update_list.clear(); dep_update_list.clear();
file_cache.clear(); //clear caches, no longer needed file_cache.clear(); //clear caches, no longer needed
@ -560,15 +559,27 @@ bool EditorFileSystem::_scan_import_support(const Vector<String> &reimports) {
return false; return false;
} }
bool EditorFileSystem::_update_scan_actions() { bool EditorFileSystem::_update_scan_actions(bool p_show_progress) {
sources_changed.clear(); sources_changed.clear();
bool fs_changed = false; bool fs_changed = false;
Vector<String> reimports; Vector<String> reimports;
Vector<String> reloads; Vector<String> reloads;
HashMap<String, String> 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) { for (const ItemAction &ia : scan_actions) {
if (editor_progress) {
editor_progress->step(ia.file, idx_action, false);
}
idx_action++;
switch (ia.action) { switch (ia.action) {
case ItemAction::ACTION_NONE: { case ItemAction::ACTION_NONE: {
} break; } break;
@ -643,10 +654,17 @@ bool EditorFileSystem::_update_scan_actions() {
if (_test_for_reimport(full_path, false)) { if (_test_for_reimport(full_path, false)) {
//must reimport //must reimport
reimports.push_back(full_path); reimports.push_back(full_path);
if (!ia.import_group_file.is_empty()) {
import_group_files[full_path] = ia.import_group_file;
}
Vector<String> dependencies = _get_dependencies(full_path); Vector<String> dependencies = _get_dependencies(full_path);
for (const String &dependency_path : dependencies) { for (const String &dependency_path : dependencies) {
if (import_extensions.has(dependency_path.get_extension())) { if (import_extensions.has(dependency_path.get_extension())) {
reimports.push_back(dependency_path); 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 { } else {
@ -676,6 +694,8 @@ bool EditorFileSystem::_update_scan_actions() {
} }
} }
memdelete_notnull(editor_progress);
if (_scan_extensions()) { if (_scan_extensions()) {
//needs editor restart //needs editor restart
//extensions also may provide filetypes to be imported, so they must run before importing //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; return true;
} }
reimport_files(reimports); _reimport_files_internal(reimports, &import_group_files);
} else { } else {
//reimport files will update the uid cache file so if nothing was reimported, update it manually //reimport files will update the uid cache file so if nothing was reimported, update it manually
ResourceUID::get_singleton()->update_cache(); ResourceUID::get_singleton()->update_cache();
@ -725,10 +745,10 @@ void EditorFileSystem::scan() {
} }
_update_extensions(); _update_extensions();
if (!use_threads) { if (!use_threads) {
scanning = true; scanning = true;
scan_total = 0; scan_total = 0;
emit_signal(SNAME("scan_started"), true);
_scan_filesystem(); _scan_filesystem();
if (filesystem) { if (filesystem) {
memdelete(filesystem); memdelete(filesystem);
@ -736,7 +756,7 @@ void EditorFileSystem::scan() {
//file_type_cache.clear(); //file_type_cache.clear();
filesystem = new_filesystem; filesystem = new_filesystem;
new_filesystem = nullptr; new_filesystem = nullptr;
_update_scan_actions(); _update_scan_actions(true);
scanning = false; scanning = false;
_update_pending_script_classes(); _update_pending_script_classes();
_update_pending_scene_groups(); _update_pending_scene_groups();
@ -749,28 +769,50 @@ void EditorFileSystem::scan() {
Thread::Settings s; Thread::Settings s;
scanning = true; scanning = true;
scan_total = 0; scan_total = 0;
emit_signal(SNAME("scan_started"), true);
s.priority = Thread::PRIORITY_LOW; s.priority = Thread::PRIORITY_LOW;
thread.start(_thread_func, this, s); thread.start(_thread_func, this, s);
//tree->hide();
//progress->show();
} }
} }
void EditorFileSystem::ScanProgress::update(int p_current, int p_total) const { void EditorFileSystem::ScanProgress::increment() {
float ratio = low + ((hi - low) / p_total) * p_current; real++;
progress->step(ratio * 1000); nb_file_to_scan--;
EditorFileSystem::singleton->scan_total = ratio; 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 { void EditorFileSystem::ScanProgress::update_estimated(int p_depth, int p_nb_sub_dirs, int p_nb_files) {
ScanProgress sp = *this; // The algorithm calculates an estimated value for the progress of scanning directories and files.
float slice = (sp.hi - sp.low) / p_total; // It adjusts the estimate based on the number of directories and files discovered so far,
sp.low += slice * p_current; // and ensures the estimated value does not decrease drastically between updates.
sp.hi = slice; float average = 10;
return sp; 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<DirAccess> &da, const ScanProgress &p_progress) { void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAccess> &da, ScanProgress *p_progress, int p_depth) {
List<String> dirs; List<String> dirs;
List<String> files; List<String> files;
@ -810,11 +852,12 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
dirs.sort_custom<FileNoCaseComparator>(); dirs.sort_custom<FileNoCaseComparator>();
files.sort_custom<FileNoCaseComparator>(); files.sort_custom<FileNoCaseComparator>();
int total = dirs.size() + files.size(); p_progress->update_estimated(p_depth, dirs.size(), files.size());
int idx = 0;
int idx = 0;
for (List<String>::Element *E = dirs.front(); E; E = E->next(), idx++) { for (List<String>::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(); String d = da->get_current_dir();
if (d == cd || !d.begins_with(cd)) { if (d == cd || !d.begins_with(cd)) {
@ -825,38 +868,27 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
efd->parent = p_dir; efd->parent = p_dir;
efd->name = E->get(); 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; // Folders are already sorted with FileNoCaseComparator.
for (int i = 0; i < p_dir->subdirs.size(); i++) { p_dir->subdirs.push_back(efd);
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);
}
da->change_dir(".."); da->change_dir("..");
} }
} else { } else {
ERR_PRINT("Cannot go into subdir '" + E->get() + "'."); ERR_PRINT("Cannot go into subdir '" + E->get() + "'.");
} }
p_progress.update(idx, total);
} }
for (List<String>::Element *E = files.front(); E; E = E->next(), idx++) { for (List<String>::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)) { if (!valid_extensions.has(ext)) {
continue; //invalid continue; //invalid
} }
EditorFileSystemDirectory::FileInfo *fi = memnew(EditorFileSystemDirectory::FileInfo); EditorFileSystemDirectory::FileInfo *fi = memnew(EditorFileSystemDirectory::FileInfo);
fi->file = E->get(); fi->file = name;
String path = cd.path_join(fi->file); String path = cd.path_join(fi->file);
@ -884,14 +916,6 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
fi->script_class_extends = fc->script_class_extends; fi->script_class_extends = fc->script_class_extends;
fi->script_class_icon_path = fc->script_class_icon_path; 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()) { if (fc->type.is_empty()) {
fi->type = ResourceLoader::get_resource_type(path); fi->type = ResourceLoader::get_resource_type(path);
fi->resource_script_class = ResourceLoader::get_resource_script_class(path); fi->resource_script_class = ResourceLoader::get_resource_script_class(path);
@ -900,15 +924,23 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
//note: I think this should not happen any longer.. //note: I think this should not happen any longer..
} }
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();
ia.import_group_file = fi->import_group_file;
scan_actions.push_back(ia);
}
if (fc->uid == ResourceUID::INVALID_ID) { if (fc->uid == ResourceUID::INVALID_ID) {
// imported files should always have a UID, so attempt to fetch it. // imported files should always have a UID, so attempt to fetch it.
fi->uid = ResourceLoader::get_resource_uid(path); fi->uid = ResourceLoader::get_resource_uid(path);
} }
} else { } else {
fi->type = ResourceFormatImporter::get_singleton()->get_resource_type(path); // Using get_resource_import_info() to prevent calling 3 times ResourceFormatImporter::_get_path_and_type.
fi->uid = ResourceFormatImporter::get_singleton()->get_resource_uid(path); ResourceFormatImporter::get_singleton()->get_resource_import_info(path, fi->type, fi->uid, fi->import_group_file);
fi->import_group_file = ResourceFormatImporter::get_singleton()->get_import_group_file(path);
fi->script_class_name = _get_global_script_class(fi->type, path, &fi->script_class_extends, &fi->script_class_icon_path); 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->modified_time = 0;
fi->import_modified_time = 0; fi->import_modified_time = 0;
@ -918,6 +950,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
ia.action = ItemAction::ACTION_FILE_TEST_REIMPORT; ia.action = ItemAction::ACTION_FILE_TEST_REIMPORT;
ia.dir = p_dir; ia.dir = p_dir;
ia.file = E->get(); ia.file = E->get();
ia.import_group_file = fi->import_group_file;
scan_actions.push_back(ia); scan_actions.push_back(ia);
} }
} else { } else {
@ -968,11 +1001,11 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
} }
p_dir->files.push_back(fi); p_dir->files.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()); uint64_t current_mtime = FileAccess::get_modified_time(p_dir->get_path());
bool updated_dir = false; bool updated_dir = false;
@ -1028,7 +1061,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
efd->name = f; efd->name = f;
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES); Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
d->change_dir(cd.path_join(f)); 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; ItemAction ia;
ia.action = ItemAction::ACTION_DIR_ADD; 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.action = ItemAction::ACTION_FILE_TEST_REIMPORT;
ia.dir = p_dir; ia.dir = p_dir;
ia.file = f; ia.file = f;
ia.import_group_file = fi->import_group_file;
scan_actions.push_back(ia); 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.action = ItemAction::ACTION_FILE_TEST_REIMPORT;
ia.dir = p_dir; ia.dir = p_dir;
ia.file = p_dir->files[i]->file; ia.file = p_dir->files[i]->file;
ia.import_group_file = p_dir->files[i]->import_group_file;
scan_actions.push_back(ia); scan_actions.push_back(ia);
} }
} else if (ResourceCache::has(path)) { //test for potential reload } 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); EditorProgressBG pr("sources", TTR("ScanSources"), 1000);
ScanProgress sp; ScanProgress sp;
sp.progress = &pr; sp.progress = &pr;
sp.hi = 1; efs->_scan_fs_changes(efs->filesystem, &sp);
sp.low = 0;
efs->_scan_fs_changes(efs->filesystem, sp);
} }
efs->scanning_changes_done.set(); efs->scanning_changes_done.set();
} }
@ -1204,10 +1237,9 @@ void EditorFileSystem::scan_changes() {
EditorProgressBG pr("sources", TTR("ScanSources"), 1000); EditorProgressBG pr("sources", TTR("ScanSources"), 1000);
ScanProgress sp; ScanProgress sp;
sp.progress = &pr; sp.progress = &pr;
sp.hi = 1;
sp.low = 0;
scan_total = 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(); bool changed = _update_scan_actions();
_update_pending_script_classes(); _update_pending_script_classes();
_update_pending_scene_groups(); _update_pending_scene_groups();
@ -1222,6 +1254,7 @@ void EditorFileSystem::scan_changes() {
ERR_FAIL_COND(thread_sources.is_started()); ERR_FAIL_COND(thread_sources.is_started());
set_process(true); set_process(true);
scan_total = 0; scan_total = 0;
emit_signal(SNAME("scan_started"), false);
Thread::Settings s; Thread::Settings s;
s.priority = Thread::PRIORITY_LOW; s.priority = Thread::PRIORITY_LOW;
thread_sources.start(_thread_func_sources, this, s); thread_sources.start(_thread_func_sources, this, s);
@ -1275,6 +1308,7 @@ void EditorFileSystem::_notification(int p_what) {
if (thread_sources.is_started()) { if (thread_sources.is_started()) {
thread_sources.wait_to_finish(); thread_sources.wait_to_finish();
} }
emit_signal(SNAME("scan_stopped"), false);
bool changed = _update_scan_actions(); bool changed = _update_scan_actions();
_update_pending_script_classes(); _update_pending_script_classes();
_update_pending_scene_groups(); _update_pending_scene_groups();
@ -1295,7 +1329,8 @@ void EditorFileSystem::_notification(int p_what) {
filesystem = new_filesystem; filesystem = new_filesystem;
new_filesystem = nullptr; new_filesystem = nullptr;
thread.wait_to_finish(); thread.wait_to_finish();
_update_scan_actions(); emit_signal(SNAME("scan_stopped"), true);
_update_scan_actions(true);
_update_pending_script_classes(); _update_pending_script_classes();
_update_pending_scene_groups(); _update_pending_scene_groups();
emit_signal(SNAME("filesystem_changed")); emit_signal(SNAME("filesystem_changed"));
@ -1578,10 +1613,20 @@ String EditorFileSystem::_get_global_script_class(const String &p_type, const St
return String(); return String();
} }
void EditorFileSystem::_update_script_classes() { void EditorFileSystem::_update_script_classes(bool p_show_progress) {
update_script_mutex.lock(); 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) { 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); EditorFileSystem::get_singleton()->register_global_class_script(path, path);
} }
@ -1590,6 +1635,10 @@ void EditorFileSystem::_update_script_classes() {
int index = -1; int index = -1;
EditorFileSystemDirectory *efd = find_file(path, &index); EditorFileSystemDirectory *efd = find_file(path, &index);
if (ep) {
ep->step(TTR("Updating documentation..."), step_count++, false);
}
if (!efd || index < 0) { if (!efd || index < 0) {
// The file was removed // The file was removed
continue; continue;
@ -1610,6 +1659,8 @@ void EditorFileSystem::_update_script_classes() {
} }
} }
memdelete_notnull(ep);
update_script_paths.clear(); update_script_paths.clear();
update_script_mutex.unlock(); update_script_mutex.unlock();
@ -1626,9 +1677,9 @@ void EditorFileSystem::_update_script_classes() {
ResourceSaver::add_custom_savers(); 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()) { if (!update_script_paths.is_empty()) {
_update_script_classes(); _update_script_classes(p_show_progress);
} else { } else {
// In case the class cache file was removed somehow, regenerate it. // In case the class cache file was removed somehow, regenerate it.
if (!FileAccess::exists(ScriptServer::get_global_class_cache_file_path())) { if (!FileAccess::exists(ScriptServer::get_global_class_cache_file_path())) {
@ -1668,7 +1719,7 @@ void EditorFileSystem::_update_scene_groups() {
} }
if (ep) { 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<String> &p_script_paths) {
fs->files.remove_at(cpos); fs->files.remove_at(cpos);
} }
_update_pending_script_classes(); // Preventing update of scripts and scene groups while first scan.
_update_pending_scene_groups(); // Some ResourceLoader resave files which invoke update_file while loading (ex: ResourceImporterCSVTranslation).
call_deferred(SNAME("emit_signal"), "filesystem_changed"); //update later if (!first_scan) {
_update_pending_script_classes();
_update_pending_scene_groups();
call_deferred(SNAME("emit_signal"), "filesystem_changed"); // Update later.
}
return; return;
} }
@ -1822,9 +1877,13 @@ void EditorFileSystem::update_files(const Vector<String> &p_script_paths) {
} }
} }
_update_pending_script_classes(); // Preventing update of scripts and scene groups while first scan.
_update_pending_scene_groups(); // Some ResourceLoader resave files which invoke update_file while loading (ex: ResourceImporterCSVTranslation).
call_deferred(SNAME("emit_signal"), "filesystem_changed"); //update later if (!first_scan) {
_update_pending_script_classes();
_update_pending_scene_groups();
call_deferred(SNAME("emit_signal"), "filesystem_changed"); // Update later.
}
} }
HashSet<String> EditorFileSystem::get_valid_extensions() const { HashSet<String> 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<String> &p_files) { void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
_reimport_files_internal(p_files, nullptr);
}
void EditorFileSystem::_reimport_files_internal(const Vector<String> &p_files, const HashMap<String, String> *p_import_group_files) {
ERR_FAIL_COND_MSG(importing, "Attempted to call reimport_files() recursively, this is not allowed."); ERR_FAIL_COND_MSG(importing, "Attempted to call reimport_files() recursively, this is not allowed.");
importing = true; importing = true;
Vector<String> reloads; Vector<String> 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<ImportFile> reimport_files; Vector<ImportFile> reimport_files;
HashMap<String, String> import_group_files = *p_import_group_files;
HashSet<String> groups_to_reimport; HashSet<String> groups_to_reimport;
for (int i = 0; i < p_files.size(); i++) { for (int i = 0; i < p_files.size(); i++) {
String file = p_files[i]; String file = p_files[i];
ResourceUID::ID uid = ResourceUID::get_singleton()->text_to_id(file); ResourceUID::ID uid = ResourceUID::get_singleton()->text_to_id(file);
if (uid != ResourceUID::INVALID_ID && ResourceUID::get_singleton()->has_id(uid)) { if (uid != ResourceUID::INVALID_ID && ResourceUID::get_singleton()->has_id(uid)) {
file = ResourceUID::get_singleton()->get_id_path(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); reimport_files.sort();
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();
#ifdef THREADS_ENABLED #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 #else
bool use_multiple_threads = false; bool use_multiple_threads = false;
#endif #endif
int from = 0; int from = 0;
for (int i = 0; i < reimport_files.size(); i++) { for (int i = 0; i < reimport_files.size(); i++) {
if (groups_to_reimport.has(reimport_files[i].path)) { if (groups_to_reimport.has(reimport_files[i].path)) {
continue; continue;
} }
if (use_multiple_threads && reimport_files[i].threaded) { if (use_multiple_threads && reimport_files[i].threaded) {
if (i + 1 == reimport_files.size() || reimport_files[i + 1].importer != reimport_files[from].importer) { if (i + 1 == reimport_files.size() || reimport_files[i + 1].importer != reimport_files[from].importer) {
if (from - i == 0) { if (from - i == 0) {
// Single file, do not use threads. // Single file, do not use threads.
pr.step(reimport_files[i].path.get_file(), i); pr.step(reimport_files[i].path.get_file(), i, false);
_reimport_file(reimport_files[i].path); _reimport_file(reimport_files[i].path);
} else { } else {
Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(reimport_files[from].importer); Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(reimport_files[from].importer);
ERR_CONTINUE(!importer.is_valid()); ERR_CONTINUE(importer.is_null());
importer->import_threaded_begin(); importer->import_threaded_begin();
ImportThreadData tdata; ImportThreadData tdata;
tdata.max_index.set(from); tdata.max_index.set(from);
tdata.reimport_from = from; tdata.reimport_from = from;
tdata.reimport_files = reimport_files.ptr(); 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)); 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; int current_index = from - 1;
do { do {
if (current_index < tdata.max_index.get()) { if (current_index < tdata.max_index.get()) {
current_index = tdata.max_index.get(); current_index = tdata.max_index.get();
pr.step(reimport_files[current_index].path.get_file(), current_index); pr.step(reimport_files[current_index].path.get_file(), current_index, false);
} }
OS::get_singleton()->delay_usec(1); OS::get_singleton()->delay_usec(1);
} while (!WorkerThreadPool::get_singleton()->is_group_task_completed(group_task)); } 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, false);
_reimport_file(reimport_files[i].path);
} 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<String, Vector<String>> group_files;
_find_group_files(filesystem, group_files, groups_to_reimport);
for (const KeyValue<String, Vector<String>> &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);
} }
} }
// Reimport groups.
from = reimport_files.size();
if (groups_to_reimport.size()) {
HashMap<String, Vector<String>> group_files;
_find_group_files(filesystem, group_files, groups_to_reimport);
for (const KeyValue<String, Vector<String>> &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. _update_pending_script_classes(true);
_save_filesystem_cache();
_update_pending_script_classes();
_update_pending_scene_groups(); _update_pending_scene_groups();
importing = false; importing = false;
if (!is_scanning()) { if (!is_scanning()) {
@ -2688,6 +2767,8 @@ void EditorFileSystem::_bind_methods() {
ADD_SIGNAL(MethodInfo("sources_changed", PropertyInfo(Variant::BOOL, "exist"))); ADD_SIGNAL(MethodInfo("sources_changed", PropertyInfo(Variant::BOOL, "exist")));
ADD_SIGNAL(MethodInfo("resources_reimported", PropertyInfo(Variant::PACKED_STRING_ARRAY, "resources"))); 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("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() { void EditorFileSystem::_update_extensions() {

View file

@ -153,6 +153,7 @@ class EditorFileSystem : public Node {
Action action = ACTION_NONE; Action action = ACTION_NONE;
EditorFileSystemDirectory *dir = nullptr; EditorFileSystemDirectory *dir = nullptr;
String file; String file;
String import_group_file;
EditorFileSystemDirectory *new_dir = nullptr; EditorFileSystemDirectory *new_dir = nullptr;
EditorFileSystemDirectory::FileInfo *new_file = nullptr; EditorFileSystemDirectory::FileInfo *new_file = nullptr;
}; };
@ -200,11 +201,15 @@ class EditorFileSystem : public Node {
HashSet<String> dep_update_list; HashSet<String> dep_update_list;
struct ScanProgress { struct ScanProgress {
float low = 0; int directories_processed = 0;
float hi = 0; int nb_dir_to_scan = 0;
mutable EditorProgressBG *progress = nullptr; int nb_file_to_scan = 0;
void update(int p_current, int p_total) const; float estimated = 0;
ScanProgress get_sub(int p_current, int p_total) const; 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(); 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; 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); void _delete_internal_files(const String &p_file);
@ -220,7 +225,7 @@ class EditorFileSystem : public Node {
HashSet<String> valid_extensions; HashSet<String> valid_extensions;
HashSet<String> import_extensions; HashSet<String> import_extensions;
void _scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAccess> &da, const ScanProgress &p_progress); void _scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAccess> &da, ScanProgress *p_progress, int p_depth);
Thread thread_sources; Thread thread_sources;
bool scanning_changes = false; bool scanning_changes = false;
@ -231,7 +236,7 @@ class EditorFileSystem : public Node {
List<String> sources_changed; List<String> sources_changed;
List<ItemAction> scan_actions; List<ItemAction> scan_actions;
bool _update_scan_actions(); bool _update_scan_actions(bool p_show_progress = false);
void _update_extensions(); void _update_extensions();
@ -257,8 +262,8 @@ class EditorFileSystem : public Node {
Mutex update_script_mutex; Mutex update_script_mutex;
HashSet<String> update_script_paths; HashSet<String> update_script_paths;
void _queue_update_script_class(const String &p_path); void _queue_update_script_class(const String &p_path);
void _update_script_classes(); void _update_script_classes(bool p_show_progress = false);
void _update_pending_script_classes(); void _update_pending_script_classes(bool p_show_progress = false);
Mutex update_scene_mutex; Mutex update_scene_mutex;
HashSet<String> update_scene_paths; HashSet<String> update_scene_paths;
@ -286,6 +291,7 @@ class EditorFileSystem : public Node {
SafeNumeric<int> max_index; SafeNumeric<int> max_index;
}; };
void _reimport_files_internal(const Vector<String> &p_files, const HashMap<String, String> *p_import_group_files);
void _reimport_thread(uint32_t p_index, ImportThreadData *p_import_data); 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); static ResourceUID::ID _resource_saver_get_resource_id_for_path(const String &p_path, bool p_generate);

View file

@ -5103,6 +5103,8 @@ void EditorNode::save_editor_layout_delayed() {
} }
void EditorNode::_load_editor_layout() { void EditorNode::_load_editor_layout() {
EditorProgress ep("loading_editor_layout", TTR("Loading editor"), 5);
ep.step("Loading editor layout...", 0, true);
Ref<ConfigFile> config; Ref<ConfigFile> config;
config.instantiate(); config.instantiate();
Error err = config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg")); 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; return;
} }
ep.step("Loading docks...", 1, true);
editor_dock_manager->load_docks_from_config(config, "docks"); editor_dock_manager->load_docks_from_config(config, "docks");
ep.step("Reopening scenes...", 2, true);
_load_open_scenes_from_config(config); _load_open_scenes_from_config(config);
ep.step("Loading central editor layout...", 3, true);
_load_central_editor_layout_from_config(config); _load_central_editor_layout_from_config(config);
ep.step("Loading plugin window layout...", 4, true);
editor_data.set_plugin_window_layout(config); editor_data.set_plugin_window_layout(config);
ep.step("Editor layout ready.", 5, true);
} }
void EditorNode::_save_central_editor_layout_to_config(Ref<ConfigFile> p_config_file) { void EditorNode::_save_central_editor_layout_to_config(Ref<ConfigFile> p_config_file) {

View file

@ -550,6 +550,8 @@ void FileSystemDock::_notification(int p_what) {
case NOTIFICATION_READY: { case NOTIFICATION_READY: {
EditorFeatureProfileManager::get_singleton()->connect("current_feature_profile_changed", callable_mp(this, &FileSystemDock::_feature_profile_changed)); 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("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)); 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)); 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(); _update_display_mode();
if (EditorFileSystem::get_singleton()->is_scanning()) { if (!EditorFileSystem::get_singleton()->is_scanning()) {
_set_scanning_mode();
} else {
_update_tree(Vector<String>(), true); _update_tree(Vector<String>(), true);
} }
} break; } break;
@ -1326,6 +1326,18 @@ void FileSystemDock::_fs_changed() {
set_process(false); 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() { void FileSystemDock::_set_scanning_mode() {
button_hist_prev->set_disabled(true); button_hist_prev->set_disabled(true);
button_hist_next->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() { void FileSystemDock::_rescan() {
_set_scanning_mode();
EditorFileSystem::get_singleton()->scan(); EditorFileSystem::get_singleton()->scan();
} }

View file

@ -308,6 +308,8 @@ private:
void _set_scanning_mode(); void _set_scanning_mode();
void _rescan(); void _rescan();
void _scan_started(bool p_complete_scan);
void _scan_stopped(bool p_complete_scan);
void _change_split_mode(); void _change_split_mode();
void _split_dragged(int p_offset); void _split_dragged(int p_offset);