diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp index b4c43abe002..a572dd562e7 100644 --- a/core/io/resource_importer.cpp +++ b/core/io/resource_importer.cpp @@ -35,6 +35,8 @@ #include "core/os/os.h" #include "core/variant/variant_parser.h" +ResourceFormatImporterLoadOnStartup ResourceImporter::load_on_startup = nullptr; + bool ResourceFormatImporter::SortImporterByName::operator()(const Ref &p_a, const Ref &p_b) const { return p_a->get_importer_name() < p_b->get_importer_name(); } @@ -137,6 +139,20 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy } Ref ResourceFormatImporter::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { +#ifdef TOOLS_ENABLED + // When loading a resource on startup, we use the load_on_startup callback, + // which executes the loading in the EditorFileSystem. It can reimport + // the resource and retry the load, allowing the resource to be loaded + // even if it is not yet imported. + if (ResourceImporter::load_on_startup != nullptr) { + return ResourceImporter::load_on_startup(this, p_path, r_error, p_use_sub_threads, r_progress, p_cache_mode); + } +#endif + + return load_internal(p_path, r_error, p_use_sub_threads, r_progress, p_cache_mode, false); +} + +Ref ResourceFormatImporter::load_internal(const String &p_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode, bool p_silence_errors) { PathAndType pat; Error err = _get_path_and_type(p_path, pat); @@ -148,6 +164,13 @@ Ref ResourceFormatImporter::load(const String &p_path, const String &p return Ref(); } + if (p_silence_errors) { + // Note: Some importers do not create files in the .godot folder, so we need to check if the path is empty. + if (!pat.path.is_empty() && !FileAccess::exists(pat.path)) { + return Ref(); + } + } + Ref res = ResourceLoader::_load(pat.path, p_path, pat.type, p_cache_mode, r_error, p_use_sub_threads, r_progress); #ifdef TOOLS_ENABLED diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h index 7b1806c3d2a..6ea5d0972ab 100644 --- a/core/io/resource_importer.h +++ b/core/io/resource_importer.h @@ -35,6 +35,9 @@ #include "core/io/resource_saver.h" class ResourceImporter; +class ResourceFormatImporter; + +typedef Ref (*ResourceFormatImporterLoadOnStartup)(ResourceFormatImporter *p_importer, const String &p_path, Error *r_error, bool p_use_sub_threads, float *r_progress, ResourceFormatLoader::CacheMode p_cache_mode); class ResourceFormatImporter : public ResourceFormatLoader { struct PathAndType { @@ -60,6 +63,7 @@ class ResourceFormatImporter : public ResourceFormatLoader { public: static ResourceFormatImporter *get_singleton() { return singleton; } virtual Ref load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override; + Ref load_internal(const String &p_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode, bool p_silence_errors); virtual void get_recognized_extensions(List *p_extensions) const override; virtual void get_recognized_extensions_for_type(const String &p_type, List *p_extensions) const override; virtual bool recognize_path(const String &p_path, const String &p_for_type = String()) const override; @@ -94,6 +98,7 @@ public: 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(); }; @@ -104,6 +109,8 @@ protected: static void _bind_methods(); public: + static ResourceFormatImporterLoadOnStartup load_on_startup; + virtual String get_importer_name() const = 0; virtual String get_visible_name() const = 0; virtual void get_recognized_extensions(List *p_extensions) const = 0; diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index bcfc29f7a3b..8cd130066e9 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -33,8 +33,6 @@ #include "core/config/project_settings.h" #include "core/extension/gdextension_manager.h" #include "core/io/file_access.h" -#include "core/io/resource_importer.h" -#include "core/io/resource_loader.h" #include "core/io/resource_saver.h" #include "core/object/worker_thread_pool.h" #include "core/os/os.h" @@ -892,6 +890,7 @@ void EditorFileSystem::scan() { // Set first_scan to false before the signals so the function doing_first_scan can return false // in editor_node to start the export if needed. first_scan = false; + ResourceImporter::load_on_startup = nullptr; emit_signal(SNAME("filesystem_changed")); emit_signal(SNAME("sources_changed"), sources_changed.size() > 0); } else { @@ -1502,6 +1501,7 @@ void EditorFileSystem::_notification(int p_what) { // Set first_scan to false before the signals so the function doing_first_scan can return false // in editor_node to start the export if needed. first_scan = false; + ResourceImporter::load_on_startup = nullptr; if (changed) { emit_signal(SNAME("filesystem_changed")); } @@ -1524,6 +1524,7 @@ void EditorFileSystem::_notification(int p_what) { // Set first_scan to false before the signals so the function doing_first_scan can return false // in editor_node to start the export if needed. first_scan = false; + ResourceImporter::load_on_startup = nullptr; emit_signal(SNAME("filesystem_changed")); emit_signal(SNAME("sources_changed"), sources_changed.size() > 0); } @@ -2401,14 +2402,16 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector return err; } -Error EditorFileSystem::_reimport_file(const String &p_file, const HashMap &p_custom_options, const String &p_custom_importer, Variant *p_generator_parameters) { +Error EditorFileSystem::_reimport_file(const String &p_file, const HashMap &p_custom_options, const String &p_custom_importer, Variant *p_generator_parameters, bool p_update_file_system) { print_verbose(vformat("EditorFileSystem: Importing file: %s", p_file)); uint64_t start_time = OS::get_singleton()->get_ticks_msec(); EditorFileSystemDirectory *fs = nullptr; int cpos = -1; - bool found = _find_file(p_file, &fs, cpos); - ERR_FAIL_COND_V_MSG(!found, ERR_FILE_NOT_FOUND, "Can't find file '" + p_file + "'."); + if (p_update_file_system) { + bool found = _find_file(p_file, &fs, cpos); + ERR_FAIL_COND_V_MSG(!found, ERR_FILE_NOT_FOUND, "Can't find file '" + p_file + "'."); + } //try to obtain existing params @@ -2462,11 +2465,13 @@ Error EditorFileSystem::_reimport_file(const String &p_file, const HashMapfiles[cpos]->modified_time = FileAccess::get_modified_time(p_file); - fs->files[cpos]->import_modified_time = FileAccess::get_modified_time(p_file + ".import"); - fs->files[cpos]->deps.clear(); - fs->files[cpos]->type = ""; - fs->files[cpos]->import_valid = false; + if (p_update_file_system) { + fs->files[cpos]->modified_time = FileAccess::get_modified_time(p_file); + fs->files[cpos]->import_modified_time = FileAccess::get_modified_time(p_file + ".import"); + fs->files[cpos]->deps.clear(); + fs->files[cpos]->type = ""; + fs->files[cpos]->import_valid = false; + } EditorResourcePreview::get_singleton()->check_for_invalidation(p_file); return OK; } @@ -2626,16 +2631,18 @@ Error EditorFileSystem::_reimport_file(const String &p_file, const HashMapfiles[cpos]->modified_time = FileAccess::get_modified_time(p_file); - fs->files[cpos]->import_modified_time = FileAccess::get_modified_time(p_file + ".import"); - fs->files[cpos]->deps = _get_dependencies(p_file); - fs->files[cpos]->type = importer->get_resource_type(); - fs->files[cpos]->uid = uid; - fs->files[cpos]->import_valid = fs->files[cpos]->type == "TextFile" ? true : ResourceLoader::is_import_valid(p_file); + // Update modified times, to avoid reimport. + fs->files[cpos]->modified_time = FileAccess::get_modified_time(p_file); + fs->files[cpos]->import_modified_time = FileAccess::get_modified_time(p_file + ".import"); + fs->files[cpos]->deps = _get_dependencies(p_file); + fs->files[cpos]->type = importer->get_resource_type(); + fs->files[cpos]->uid = uid; + fs->files[cpos]->import_valid = fs->files[cpos]->type == "TextFile" ? true : ResourceLoader::is_import_valid(p_file); + } if (ResourceUID::get_singleton()->has_id(uid)) { ResourceUID::get_singleton()->set_id(uid, p_file); @@ -2879,6 +2886,33 @@ Error EditorFileSystem::_resource_import(const String &p_path) { return OK; } +Ref EditorFileSystem::_load_resource_on_startup(ResourceFormatImporter *p_importer, const String &p_path, Error *r_error, bool p_use_sub_threads, float *r_progress, ResourceFormatLoader::CacheMode p_cache_mode) { + ERR_FAIL_NULL_V(p_importer, Ref()); + + if (!FileAccess::exists(p_path)) { + ERR_FAIL_V_MSG(Ref(), vformat("Failed loading resource: %s. The file doesn't seem to exist.", p_path)); + } + + Ref res; + bool can_retry = true; + bool retry = true; + while (retry) { + retry = false; + + res = p_importer->load_internal(p_path, r_error, p_use_sub_threads, r_progress, p_cache_mode, can_retry); + + if (res.is_null() && can_retry) { + can_retry = false; + Error err = singleton->_reimport_file(p_path, HashMap(), "", nullptr, false); + if (err == OK) { + retry = true; + } + } + } + + return res; +} + bool EditorFileSystem::_should_skip_directory(const String &p_path) { String project_data_path = ProjectSettings::get_singleton()->get_project_data_path(); if (p_path == project_data_path || p_path.begins_with(project_data_path + "/")) { @@ -3126,6 +3160,10 @@ EditorFileSystem::EditorFileSystem() { scan_total = 0; ResourceSaver::set_get_resource_id_for_path(_resource_saver_get_resource_id_for_path); + + // Set the callback method that the ResourceFormatImporter will use + // if resources are loaded during the first scan. + ResourceImporter::load_on_startup = _load_resource_on_startup; } EditorFileSystem::~EditorFileSystem() { diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h index 1bc24416ebc..e1e0d83bfb3 100644 --- a/editor/editor_file_system.h +++ b/editor/editor_file_system.h @@ -32,6 +32,8 @@ #define EDITOR_FILE_SYSTEM_H #include "core/io/dir_access.h" +#include "core/io/resource_importer.h" +#include "core/io/resource_loader.h" #include "core/os/thread.h" #include "core/os/thread_safe.h" #include "core/templates/hash_set.h" @@ -252,7 +254,7 @@ class EditorFileSystem : public Node { void _update_extensions(); - Error _reimport_file(const String &p_file, const HashMap &p_custom_options = HashMap(), const String &p_custom_importer = String(), Variant *generator_parameters = nullptr); + Error _reimport_file(const String &p_file, const HashMap &p_custom_options = HashMap(), const String &p_custom_importer = String(), Variant *generator_parameters = nullptr, bool p_update_file_system = true); Error _reimport_group(const String &p_group_file, const Vector &p_files); bool _test_for_reimport(const String &p_path, bool p_only_imported_files); @@ -296,6 +298,7 @@ class EditorFileSystem : public Node { String _get_global_script_class(const String &p_type, const String &p_path, String *r_extends, String *r_icon_path) const; static Error _resource_import(const String &p_path); + static Ref _load_resource_on_startup(ResourceFormatImporter *p_importer, const String &p_path, Error *r_error, bool p_use_sub_threads, float *r_progress, ResourceFormatLoader::CacheMode p_cache_mode); bool using_fat32_or_exfat; // Workaround for projects in FAT32 or exFAT filesystem (pendrives, most of the time)