You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-04 12:00:25 +00:00
Fix accessing UID before first scan
This commit is contained in:
@@ -154,6 +154,19 @@ String ResourceUID::get_id_path(ID p_id) const {
|
|||||||
ERR_FAIL_COND_V_MSG(p_id == INVALID_ID, String(), "Invalid UID.");
|
ERR_FAIL_COND_V_MSG(p_id == INVALID_ID, String(), "Invalid UID.");
|
||||||
MutexLock l(mutex);
|
MutexLock l(mutex);
|
||||||
const ResourceUID::Cache *cache = unique_ids.getptr(p_id);
|
const ResourceUID::Cache *cache = unique_ids.getptr(p_id);
|
||||||
|
|
||||||
|
#if TOOLS_ENABLED
|
||||||
|
// On startup, the scan_for_uid_on_startup callback should be set and will
|
||||||
|
// execute EditorFileSystem::scan_for_uid, which scans all project files
|
||||||
|
// to reload the UID cache before the first scan.
|
||||||
|
// Note: EditorFileSystem::scan_for_uid sets scan_for_uid_on_startup to nullptr
|
||||||
|
// once the first scan_for_uid is complete.
|
||||||
|
if (!cache && scan_for_uid_on_startup) {
|
||||||
|
scan_for_uid_on_startup();
|
||||||
|
cache = unique_ids.getptr(p_id);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ERR_FAIL_COND_V_MSG(!cache, String(), vformat("Unrecognized UID: \"%s\".", id_to_text(p_id)));
|
ERR_FAIL_COND_V_MSG(!cache, String(), vformat("Unrecognized UID: \"%s\".", id_to_text(p_id)));
|
||||||
const CharString &cs = cache->cs;
|
const CharString &cs = cache->cs;
|
||||||
return String::utf8(cs.ptr());
|
return String::utf8(cs.ptr());
|
||||||
|
|||||||
@@ -37,6 +37,8 @@
|
|||||||
|
|
||||||
class FileAccess;
|
class FileAccess;
|
||||||
|
|
||||||
|
typedef void (*ResourceUIDScanForUIDOnStartup)();
|
||||||
|
|
||||||
class ResourceUID : public Object {
|
class ResourceUID : public Object {
|
||||||
GDCLASS(ResourceUID, Object)
|
GDCLASS(ResourceUID, Object)
|
||||||
public:
|
public:
|
||||||
@@ -63,6 +65,8 @@ protected:
|
|||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
inline static ResourceUIDScanForUIDOnStartup scan_for_uid_on_startup = nullptr;
|
||||||
|
|
||||||
String id_to_text(ID p_id) const;
|
String id_to_text(ID p_id) const;
|
||||||
ID text_to_id(const String &p_text) const;
|
ID text_to_id(const String &p_text) const;
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,9 @@
|
|||||||
#include "scene/resources/packed_scene.h"
|
#include "scene/resources/packed_scene.h"
|
||||||
|
|
||||||
EditorFileSystem *EditorFileSystem::singleton = nullptr;
|
EditorFileSystem *EditorFileSystem::singleton = nullptr;
|
||||||
|
int EditorFileSystem::nb_files_total = 0;
|
||||||
|
EditorFileSystem::ScannedDirectory *EditorFileSystem::first_scan_root_dir = nullptr;
|
||||||
|
|
||||||
//the name is the version, to keep compatibility with different versions of Godot
|
//the name is the version, to keep compatibility with different versions of Godot
|
||||||
#define CACHE_FILE_NAME "filesystem_cache10"
|
#define CACHE_FILE_NAME "filesystem_cache10"
|
||||||
|
|
||||||
@@ -237,16 +240,72 @@ EditorFileSystem::ScannedDirectory::~ScannedDirectory() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorFileSystem::_first_scan_filesystem() {
|
void EditorFileSystem::_load_first_scan_root_dir() {
|
||||||
EditorProgress ep = EditorProgress("first_scan_filesystem", TTR("Project initialization"), 5);
|
|
||||||
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
||||||
first_scan_root_dir = memnew(ScannedDirectory);
|
first_scan_root_dir = memnew(ScannedDirectory);
|
||||||
first_scan_root_dir->full_path = "res://";
|
first_scan_root_dir->full_path = "res://";
|
||||||
|
|
||||||
|
nb_files_total = _scan_new_dir(first_scan_root_dir, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorFileSystem::scan_for_uid() {
|
||||||
|
// Load file structure into memory.
|
||||||
|
_load_first_scan_root_dir();
|
||||||
|
|
||||||
|
// Load extensions for which an .import should exists.
|
||||||
|
List<String> extensionsl;
|
||||||
|
HashSet<String> import_extensions;
|
||||||
|
ResourceFormatImporter::get_singleton()->get_recognized_extensions(&extensionsl);
|
||||||
|
for (const String &E : extensionsl) {
|
||||||
|
import_extensions.insert(E);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan the file system to load uid.
|
||||||
|
_scan_for_uid_directory(first_scan_root_dir, import_extensions);
|
||||||
|
|
||||||
|
// It's done, resetting the callback method to prevent a second scan.
|
||||||
|
ResourceUID::scan_for_uid_on_startup = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorFileSystem::_scan_for_uid_directory(const ScannedDirectory *p_scan_dir, const HashSet<String> &p_import_extensions) {
|
||||||
|
for (ScannedDirectory *scan_sub_dir : p_scan_dir->subdirs) {
|
||||||
|
_scan_for_uid_directory(scan_sub_dir, p_import_extensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const String &scan_file : p_scan_dir->files) {
|
||||||
|
const String ext = scan_file.get_extension().to_lower();
|
||||||
|
|
||||||
|
if (ext == "uid" || ext == "import") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const String path = p_scan_dir->full_path.path_join(scan_file);
|
||||||
|
ResourceUID::ID uid = ResourceUID::INVALID_ID;
|
||||||
|
if (p_import_extensions.has(ext)) {
|
||||||
|
if (FileAccess::exists(path + ".import")) {
|
||||||
|
uid = ResourceFormatImporter::get_singleton()->get_resource_uid(path);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uid = ResourceLoader::get_resource_uid(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uid != ResourceUID::INVALID_ID) {
|
||||||
|
if (!ResourceUID::get_singleton()->has_id(uid)) {
|
||||||
|
ResourceUID::get_singleton()->add_id(uid, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorFileSystem::_first_scan_filesystem() {
|
||||||
|
EditorProgress ep = EditorProgress("first_scan_filesystem", TTR("Project initialization"), 5);
|
||||||
HashSet<String> existing_class_names;
|
HashSet<String> existing_class_names;
|
||||||
HashSet<String> extensions;
|
HashSet<String> extensions;
|
||||||
|
|
||||||
ep.step(TTR("Scanning file structure..."), 0, true);
|
if (!first_scan_root_dir) {
|
||||||
nb_files_total = _scan_new_dir(first_scan_root_dir, d);
|
ep.step(TTR("Scanning file structure..."), 0, true);
|
||||||
|
_load_first_scan_root_dir();
|
||||||
|
}
|
||||||
|
|
||||||
// Preloading GDExtensions file extensions to prevent looping on all the resource loaders
|
// Preloading GDExtensions file extensions to prevent looping on all the resource loaders
|
||||||
// for each files in _first_scan_process_scripts.
|
// for each files in _first_scan_process_scripts.
|
||||||
@@ -440,6 +499,7 @@ void EditorFileSystem::_scan_filesystem() {
|
|||||||
sd = first_scan_root_dir;
|
sd = first_scan_root_dir;
|
||||||
// Will be updated on scan.
|
// Will be updated on scan.
|
||||||
ResourceUID::get_singleton()->clear();
|
ResourceUID::get_singleton()->clear();
|
||||||
|
ResourceUID::scan_for_uid_on_startup = nullptr;
|
||||||
processed_files = memnew(HashSet<String>());
|
processed_files = memnew(HashSet<String>());
|
||||||
} else {
|
} else {
|
||||||
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ class EditorFileSystem : public Node {
|
|||||||
static void _thread_func(void *_userdata);
|
static void _thread_func(void *_userdata);
|
||||||
|
|
||||||
EditorFileSystemDirectory *new_filesystem = nullptr;
|
EditorFileSystemDirectory *new_filesystem = nullptr;
|
||||||
ScannedDirectory *first_scan_root_dir = nullptr;
|
static ScannedDirectory *first_scan_root_dir;
|
||||||
|
|
||||||
bool filesystem_changed_queued = false;
|
bool filesystem_changed_queued = false;
|
||||||
bool scanning = false;
|
bool scanning = false;
|
||||||
@@ -192,13 +192,17 @@ class EditorFileSystem : public Node {
|
|||||||
float scan_total;
|
float scan_total;
|
||||||
String filesystem_settings_version_for_import;
|
String filesystem_settings_version_for_import;
|
||||||
bool revalidate_import_files = false;
|
bool revalidate_import_files = false;
|
||||||
int nb_files_total = 0;
|
static int nb_files_total;
|
||||||
|
|
||||||
void _notify_filesystem_changed();
|
void _notify_filesystem_changed();
|
||||||
void _scan_filesystem();
|
void _scan_filesystem();
|
||||||
void _first_scan_filesystem();
|
void _first_scan_filesystem();
|
||||||
void _first_scan_process_scripts(const ScannedDirectory *p_scan_dir, List<String> &p_gdextension_extensions, HashSet<String> &p_existing_class_names, HashSet<String> &p_extensions);
|
void _first_scan_process_scripts(const ScannedDirectory *p_scan_dir, List<String> &p_gdextension_extensions, HashSet<String> &p_existing_class_names, HashSet<String> &p_extensions);
|
||||||
|
|
||||||
|
static void _scan_for_uid_directory(const ScannedDirectory *p_scan_dir, const HashSet<String> &p_import_extensions);
|
||||||
|
|
||||||
|
static void _load_first_scan_root_dir();
|
||||||
|
|
||||||
HashSet<String> late_update_files;
|
HashSet<String> late_update_files;
|
||||||
|
|
||||||
void _save_late_updated_files();
|
void _save_late_updated_files();
|
||||||
@@ -255,7 +259,7 @@ class EditorFileSystem : public Node {
|
|||||||
HashSet<String> valid_extensions;
|
HashSet<String> valid_extensions;
|
||||||
HashSet<String> import_extensions;
|
HashSet<String> import_extensions;
|
||||||
|
|
||||||
int _scan_new_dir(ScannedDirectory *p_dir, Ref<DirAccess> &da);
|
static int _scan_new_dir(ScannedDirectory *p_dir, Ref<DirAccess> &da);
|
||||||
void _process_file_system(const ScannedDirectory *p_scan_dir, EditorFileSystemDirectory *p_dir, ScanProgress &p_progress, HashSet<String> *p_processed_files);
|
void _process_file_system(const ScannedDirectory *p_scan_dir, EditorFileSystemDirectory *p_dir, ScanProgress &p_progress, HashSet<String> *p_processed_files);
|
||||||
|
|
||||||
Thread thread_sources;
|
Thread thread_sources;
|
||||||
@@ -412,6 +416,8 @@ public:
|
|||||||
|
|
||||||
static bool _should_skip_directory(const String &p_path);
|
static bool _should_skip_directory(const String &p_path);
|
||||||
|
|
||||||
|
static void scan_for_uid();
|
||||||
|
|
||||||
void add_import_format_support_query(Ref<EditorFileSystemImportFormatSupportQuery> p_query);
|
void add_import_format_support_query(Ref<EditorFileSystemImportFormatSupportQuery> p_query);
|
||||||
void remove_import_format_support_query(Ref<EditorFileSystemImportFormatSupportQuery> p_query);
|
void remove_import_format_support_query(Ref<EditorFileSystemImportFormatSupportQuery> p_query);
|
||||||
EditorFileSystem();
|
EditorFileSystem();
|
||||||
|
|||||||
@@ -3444,6 +3444,17 @@ Error Main::setup2(bool p_show_boot_logo) {
|
|||||||
// This loads global classes, so it must happen before custom loaders and savers are registered
|
// This loads global classes, so it must happen before custom loaders and savers are registered
|
||||||
ScriptServer::init_languages();
|
ScriptServer::init_languages();
|
||||||
|
|
||||||
|
#if TOOLS_ENABLED
|
||||||
|
|
||||||
|
// Setting up the callback to execute a scan for UIDs on disk when a UID
|
||||||
|
// does not exist in the UID cache on startup. This prevents invalid UID errors
|
||||||
|
// when opening a project without a UID cache file or with an invalid cache.
|
||||||
|
if (editor) {
|
||||||
|
ResourceUID::scan_for_uid_on_startup = EditorFileSystem::scan_for_uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
theme_db->initialize_theme();
|
theme_db->initialize_theme();
|
||||||
audio_server->load_default_bus_layout();
|
audio_server->load_default_bus_layout();
|
||||||
|
|
||||||
@@ -3496,9 +3507,21 @@ void Main::setup_boot_logo() {
|
|||||||
|
|
||||||
if (show_logo) { //boot logo!
|
if (show_logo) { //boot logo!
|
||||||
const bool boot_logo_image = GLOBAL_DEF_BASIC("application/boot_splash/show_image", true);
|
const bool boot_logo_image = GLOBAL_DEF_BASIC("application/boot_splash/show_image", true);
|
||||||
const String boot_logo_path = ResourceUID::ensure_path(GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "application/boot_splash/image", PROPERTY_HINT_FILE, "*.png"), String())).strip_edges();
|
|
||||||
const bool boot_logo_scale = GLOBAL_DEF_BASIC("application/boot_splash/fullsize", true);
|
const bool boot_logo_scale = GLOBAL_DEF_BASIC("application/boot_splash/fullsize", true);
|
||||||
const bool boot_logo_filter = GLOBAL_DEF_BASIC("application/boot_splash/use_filter", true);
|
const bool boot_logo_filter = GLOBAL_DEF_BASIC("application/boot_splash/use_filter", true);
|
||||||
|
String boot_logo_path = GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "application/boot_splash/image", PROPERTY_HINT_FILE, "*.png"), String());
|
||||||
|
|
||||||
|
// If the UID cache is missing or invalid, it could be 'normal' for the UID to not exist in memory.
|
||||||
|
// It's too soon to scan the project files since the ResourceFormatImporter is not loaded yet,
|
||||||
|
// so to prevent printing errors, we will just skip the custom boot logo this time.
|
||||||
|
if (boot_logo_path.begins_with("uid://")) {
|
||||||
|
const ResourceUID::ID logo_id = ResourceUID::get_singleton()->text_to_id(boot_logo_path);
|
||||||
|
if (ResourceUID::get_singleton()->has_id(logo_id)) {
|
||||||
|
boot_logo_path = ResourceUID::get_singleton()->get_id_path(logo_id).strip_edges();
|
||||||
|
} else {
|
||||||
|
boot_logo_path = String();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ref<Image> boot_logo;
|
Ref<Image> boot_logo;
|
||||||
|
|
||||||
@@ -4215,7 +4238,7 @@ int Main::start() {
|
|||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
if (editor) {
|
if (editor) {
|
||||||
if (!recovery_mode && (game_path != String(GLOBAL_GET("application/run/main_scene")) || !editor_node->has_scenes_in_session())) {
|
if (!recovery_mode && (game_path != ResourceUID::ensure_path(String(GLOBAL_GET("application/run/main_scene"))) || !editor_node->has_scenes_in_session())) {
|
||||||
Error serr = editor_node->load_scene(local_game_path);
|
Error serr = editor_node->load_scene(local_game_path);
|
||||||
if (serr != OK) {
|
if (serr != OK) {
|
||||||
ERR_PRINT("Failed to load scene");
|
ERR_PRINT("Failed to load scene");
|
||||||
|
|||||||
Reference in New Issue
Block a user