Skip to content

Commit 2ed5415

Browse files
committed
Fix accessing UID before first scan
1 parent 06acfcc commit 2ed5415

File tree

5 files changed

+110
-9
lines changed

5 files changed

+110
-9
lines changed

core/io/resource_uid.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,19 @@ String ResourceUID::get_id_path(ID p_id) const {
154154
ERR_FAIL_COND_V_MSG(p_id == INVALID_ID, String(), "Invalid UID.");
155155
MutexLock l(mutex);
156156
const ResourceUID::Cache *cache = unique_ids.getptr(p_id);
157+
158+
#if TOOLS_ENABLED
159+
// On startup, the scan_for_uid_on_startup callback should be set and will
160+
// execute EditorFileSystem::scan_for_uid, which scans all project files
161+
// to reload the UID cache before the first scan.
162+
// Note: EditorFileSystem::scan_for_uid sets scan_for_uid_on_startup to nullptr
163+
// once the first scan_for_uid is complete.
164+
if (!cache && scan_for_uid_on_startup) {
165+
scan_for_uid_on_startup();
166+
cache = unique_ids.getptr(p_id);
167+
}
168+
#endif
169+
157170
ERR_FAIL_COND_V_MSG(!cache, String(), vformat("Unrecognized UID: \"%s\".", id_to_text(p_id)));
158171
const CharString &cs = cache->cs;
159172
return String::utf8(cs.ptr());

core/io/resource_uid.h

+4
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737

3838
class FileAccess;
3939

40+
typedef void (*ResourceUIDScanForUIDOnStartup)();
41+
4042
class ResourceUID : public Object {
4143
GDCLASS(ResourceUID, Object)
4244
public:
@@ -63,6 +65,8 @@ class ResourceUID : public Object {
6365
static void _bind_methods();
6466

6567
public:
68+
inline static ResourceUIDScanForUIDOnStartup scan_for_uid_on_startup = nullptr;
69+
6670
String id_to_text(ID p_id) const;
6771
ID text_to_id(const String &p_text) const;
6872

editor/editor_file_system.cpp

+64-4
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@
4848
#include "scene/resources/packed_scene.h"
4949

5050
EditorFileSystem *EditorFileSystem::singleton = nullptr;
51+
int EditorFileSystem::nb_files_total = 0;
52+
EditorFileSystem::ScannedDirectory *EditorFileSystem::first_scan_root_dir = nullptr;
53+
5154
//the name is the version, to keep compatibility with different versions of Godot
5255
#define CACHE_FILE_NAME "filesystem_cache10"
5356

@@ -237,16 +240,72 @@ EditorFileSystem::ScannedDirectory::~ScannedDirectory() {
237240
}
238241
}
239242

240-
void EditorFileSystem::_first_scan_filesystem() {
241-
EditorProgress ep = EditorProgress("first_scan_filesystem", TTR("Project initialization"), 5);
243+
void EditorFileSystem::_load_first_scan_root_dir() {
242244
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
243245
first_scan_root_dir = memnew(ScannedDirectory);
244246
first_scan_root_dir->full_path = "res://";
247+
248+
nb_files_total = _scan_new_dir(first_scan_root_dir, d);
249+
}
250+
251+
void EditorFileSystem::scan_for_uid() {
252+
// Load file structure into memory.
253+
_load_first_scan_root_dir();
254+
255+
// Load extensions for which an .import should exists.
256+
List<String> extensionsl;
257+
HashSet<String> import_extensions;
258+
ResourceFormatImporter::get_singleton()->get_recognized_extensions(&extensionsl);
259+
for (const String &E : extensionsl) {
260+
import_extensions.insert(E);
261+
}
262+
263+
// Scan the file system to load uid.
264+
_scan_for_uid_directory(first_scan_root_dir, import_extensions);
265+
266+
// It's done, resetting the callback method to prevent a second scan.
267+
ResourceUID::scan_for_uid_on_startup = nullptr;
268+
}
269+
270+
void EditorFileSystem::_scan_for_uid_directory(const ScannedDirectory *p_scan_dir, const HashSet<String> &p_import_extensions) {
271+
for (ScannedDirectory *scan_sub_dir : p_scan_dir->subdirs) {
272+
_scan_for_uid_directory(scan_sub_dir, p_import_extensions);
273+
}
274+
275+
for (const String &scan_file : p_scan_dir->files) {
276+
const String ext = scan_file.get_extension().to_lower();
277+
278+
if (ext == "uid" || ext == "import") {
279+
continue;
280+
}
281+
282+
const String path = p_scan_dir->full_path.path_join(scan_file);
283+
ResourceUID::ID uid = ResourceUID::INVALID_ID;
284+
if (p_import_extensions.has(ext)) {
285+
if (FileAccess::exists(path + ".import")) {
286+
uid = ResourceFormatImporter::get_singleton()->get_resource_uid(path);
287+
}
288+
} else {
289+
uid = ResourceLoader::get_resource_uid(path);
290+
}
291+
292+
if (uid != ResourceUID::INVALID_ID) {
293+
if (!ResourceUID::get_singleton()->has_id(uid)) {
294+
ResourceUID::get_singleton()->add_id(uid, path);
295+
}
296+
}
297+
}
298+
}
299+
300+
void EditorFileSystem::_first_scan_filesystem() {
301+
EditorProgress ep = EditorProgress("first_scan_filesystem", TTR("Project initialization"), 5);
245302
HashSet<String> existing_class_names;
246303
HashSet<String> extensions;
247304

248-
ep.step(TTR("Scanning file structure..."), 0, true);
249-
nb_files_total = _scan_new_dir(first_scan_root_dir, d);
305+
if (!first_scan_root_dir) {
306+
ep.step(TTR("Scanning file structure..."), 0, true);
307+
_load_first_scan_root_dir();
308+
}
250309

251310
// Preloading GDExtensions file extensions to prevent looping on all the resource loaders
252311
// for each files in _first_scan_process_scripts.
@@ -440,6 +499,7 @@ void EditorFileSystem::_scan_filesystem() {
440499
sd = first_scan_root_dir;
441500
// Will be updated on scan.
442501
ResourceUID::get_singleton()->clear();
502+
ResourceUID::scan_for_uid_on_startup = nullptr;
443503
processed_files = memnew(HashSet<String>());
444504
} else {
445505
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES);

editor/editor_file_system.h

+9-3
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ class EditorFileSystem : public Node {
182182
static void _thread_func(void *_userdata);
183183

184184
EditorFileSystemDirectory *new_filesystem = nullptr;
185-
ScannedDirectory *first_scan_root_dir = nullptr;
185+
static ScannedDirectory *first_scan_root_dir;
186186

187187
bool filesystem_changed_queued = false;
188188
bool scanning = false;
@@ -192,13 +192,17 @@ class EditorFileSystem : public Node {
192192
float scan_total;
193193
String filesystem_settings_version_for_import;
194194
bool revalidate_import_files = false;
195-
int nb_files_total = 0;
195+
static int nb_files_total;
196196

197197
void _notify_filesystem_changed();
198198
void _scan_filesystem();
199199
void _first_scan_filesystem();
200200
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);
201201

202+
static void _scan_for_uid_directory(const ScannedDirectory *p_scan_dir, const HashSet<String> &p_import_extensions);
203+
204+
static void _load_first_scan_root_dir();
205+
202206
HashSet<String> late_update_files;
203207

204208
void _save_late_updated_files();
@@ -255,7 +259,7 @@ class EditorFileSystem : public Node {
255259
HashSet<String> valid_extensions;
256260
HashSet<String> import_extensions;
257261

258-
int _scan_new_dir(ScannedDirectory *p_dir, Ref<DirAccess> &da);
262+
static int _scan_new_dir(ScannedDirectory *p_dir, Ref<DirAccess> &da);
259263
void _process_file_system(const ScannedDirectory *p_scan_dir, EditorFileSystemDirectory *p_dir, ScanProgress &p_progress, HashSet<String> *p_processed_files);
260264

261265
Thread thread_sources;
@@ -412,6 +416,8 @@ class EditorFileSystem : public Node {
412416

413417
static bool _should_skip_directory(const String &p_path);
414418

419+
static void scan_for_uid();
420+
415421
void add_import_format_support_query(Ref<EditorFileSystemImportFormatSupportQuery> p_query);
416422
void remove_import_format_support_query(Ref<EditorFileSystemImportFormatSupportQuery> p_query);
417423
EditorFileSystem();

main/main.cpp

+20-2
Original file line numberDiff line numberDiff line change
@@ -3444,6 +3444,17 @@ Error Main::setup2(bool p_show_boot_logo) {
34443444
// This loads global classes, so it must happen before custom loaders and savers are registered
34453445
ScriptServer::init_languages();
34463446

3447+
#if TOOLS_ENABLED
3448+
3449+
// Setting up the callback to execute a scan for UIDs on disk when a UID
3450+
// does not exist in the UID cache on startup. This prevents invalid UID errors
3451+
// when opening a project without a UID cache file or with an invalid cache.
3452+
if (editor) {
3453+
ResourceUID::scan_for_uid_on_startup = EditorFileSystem::scan_for_uid;
3454+
}
3455+
3456+
#endif
3457+
34473458
theme_db->initialize_theme();
34483459
audio_server->load_default_bus_layout();
34493460

@@ -3496,9 +3507,16 @@ void Main::setup_boot_logo() {
34963507

34973508
if (show_logo) { //boot logo!
34983509
const bool boot_logo_image = GLOBAL_DEF_BASIC("application/boot_splash/show_image", true);
3499-
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();
35003510
const bool boot_logo_scale = GLOBAL_DEF_BASIC("application/boot_splash/fullsize", true);
35013511
const bool boot_logo_filter = GLOBAL_DEF_BASIC("application/boot_splash/use_filter", true);
3512+
String boot_logo_path = GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "application/boot_splash/image", PROPERTY_HINT_FILE, "*.png"), String());
3513+
3514+
// If the UID cache is missing or invalid, it could be 'normal' for the UID to not exist in memory.
3515+
// It's too soon to scan the project files since the ResourceFormatImporter is not loaded yet,
3516+
// so to prevent printing errors, we will just skip the custom boot logo this time.
3517+
if (boot_logo_path.begins_with("uid://") && ResourceUID::get_singleton()->has_id(ResourceUID::get_singleton()->text_to_id(boot_logo_path))) {
3518+
boot_logo_path = ResourceUID::ensure_path(boot_logo_path).strip_edges();
3519+
}
35023520

35033521
Ref<Image> boot_logo;
35043522

@@ -4215,7 +4233,7 @@ int Main::start() {
42154233

42164234
#ifdef TOOLS_ENABLED
42174235
if (editor) {
4218-
if (!recovery_mode && (game_path != String(GLOBAL_GET("application/run/main_scene")) || !editor_node->has_scenes_in_session())) {
4236+
if (!recovery_mode && (game_path != ResourceUID::ensure_path(String(GLOBAL_GET("application/run/main_scene"))) || !editor_node->has_scenes_in_session())) {
42194237
Error serr = editor_node->load_scene(local_game_path);
42204238
if (serr != OK) {
42214239
ERR_PRINT("Failed to load scene");

0 commit comments

Comments
 (0)