diff --git a/core/io/resource_uid.cpp b/core/io/resource_uid.cpp index 8378ec7b4cc..ef997f7458c 100644 --- a/core/io/resource_uid.cpp +++ b/core/io/resource_uid.cpp @@ -35,6 +35,7 @@ #include "core/io/dir_access.h" #include "core/io/file_access.h" #include "core/io/resource_loader.h" +#include "core/math/random_pcg.h" // These constants are off by 1, causing the 'z' and '9' characters never to be used. // This cannot be fixed without breaking compatibility; see GH-83843. @@ -121,10 +122,31 @@ ResourceUID::ID ResourceUID::create_id() { } } +ResourceUID::ID ResourceUID::create_id_for_path(const String &p_path) { + ID id = INVALID_ID; + RandomPCG rng; + + const String project_name = GLOBAL_GET("application/config/name"); + rng.seed(project_name.hash64() * p_path.hash64() * FileAccess::get_md5(p_path).hash64()); + + while (true) { + int64_t num1 = rng.rand(); + int64_t num2 = ((int64_t)rng.rand()) << 32; + id = (num1 | num2) & 0x7FFFFFFFFFFFFFFF; + + MutexLock lock(mutex); + if (!unique_ids.has(id)) { + break; + } + } + return id; +} + bool ResourceUID::has_id(ID p_id) const { MutexLock l(mutex); return unique_ids.has(p_id); } + void ResourceUID::add_id(ID p_id, const String &p_path) { MutexLock l(mutex); ERR_FAIL_COND(unique_ids.has(p_id)); @@ -327,6 +349,7 @@ void ResourceUID::_bind_methods() { ClassDB::bind_method(D_METHOD("text_to_id", "text_id"), &ResourceUID::text_to_id); ClassDB::bind_method(D_METHOD("create_id"), &ResourceUID::create_id); + ClassDB::bind_method(D_METHOD("create_id_for_path", "path"), &ResourceUID::create_id_for_path); ClassDB::bind_method(D_METHOD("has_id", "id"), &ResourceUID::has_id); ClassDB::bind_method(D_METHOD("add_id", "id", "path"), &ResourceUID::add_id); diff --git a/core/io/resource_uid.h b/core/io/resource_uid.h index 06196212e27..6ac4c9c998b 100644 --- a/core/io/resource_uid.h +++ b/core/io/resource_uid.h @@ -70,6 +70,7 @@ public: ID text_to_id(const String &p_text) const; ID create_id(); + ID create_id_for_path(const String &p_path); bool has_id(ID p_id) const; void add_id(ID p_id, const String &p_path); void set_id(ID p_id, const String &p_path); diff --git a/doc/classes/ResourceUID.xml b/doc/classes/ResourceUID.xml index 24853d462d2..a87fb32898a 100644 --- a/doc/classes/ResourceUID.xml +++ b/doc/classes/ResourceUID.xml @@ -26,6 +26,13 @@ In order for this UID to be registered, you must call [method add_id] or [method set_id]. + + + + + Like [method create_id], but the UID is seeded with the provided [param path] and project name. UIDs generated for that path will be always the same within the current project. + + diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 990a3f1c391..066d8e0451b 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -905,7 +905,7 @@ bool EditorFileSystem::_update_scan_actions() { if (existing_id != ResourceUID::INVALID_ID) { const String old_path = ResourceUID::get_singleton()->get_id_path(existing_id); if (old_path != new_file_path && FileAccess::exists(old_path)) { - const ResourceUID::ID new_id = ResourceUID::get_singleton()->create_id(); + const ResourceUID::ID new_id = ResourceUID::get_singleton()->create_id_for_path(new_file_path); ResourceUID::get_singleton()->add_id(new_id, new_file_path); ResourceSaver::set_uid(new_file_path, new_id); WARN_PRINT(vformat("Duplicate UID detected for Resource at \"%s\".\nOld Resource path: \"%s\". The new file UID was changed automatically.", new_file_path, old_path)); @@ -916,7 +916,7 @@ bool EditorFileSystem::_update_scan_actions() { } else if (ResourceLoader::should_create_uid_file(new_file_path)) { Ref f = FileAccess::open(new_file_path + ".uid", FileAccess::WRITE); if (f.is_valid()) { - ia.new_file->uid = ResourceUID::get_singleton()->create_id(); + ia.new_file->uid = ResourceUID::get_singleton()->create_id_for_path(new_file_path); f->store_line(ResourceUID::get_singleton()->id_to_text(ia.new_file->uid)); } } @@ -1353,7 +1353,7 @@ void EditorFileSystem::_process_file_system(const ScannedDirectory *p_scan_dir, Ref f = FileAccess::open(path + ".uid", FileAccess::WRITE); if (f.is_valid()) { if (fi->uid == ResourceUID::INVALID_ID) { - fi->uid = ResourceUID::get_singleton()->create_id(); + fi->uid = ResourceUID::get_singleton()->create_id_for_path(path); } else { WARN_PRINT(vformat("Missing .uid file for path \"%s\". The file was re-created from cache.", path)); } @@ -2442,7 +2442,7 @@ void EditorFileSystem::update_files(const Vector &p_script_paths) { if (ResourceLoader::should_create_uid_file(file)) { Ref f = FileAccess::open(file + ".uid", FileAccess::WRITE); if (f.is_valid()) { - const ResourceUID::ID id = ResourceUID::get_singleton()->create_id(); + const ResourceUID::ID id = ResourceUID::get_singleton()->create_id_for_path(file); ResourceUID::get_singleton()->add_id(id, file); f->store_line(ResourceUID::get_singleton()->id_to_text(id)); fi->uid = id; @@ -2630,7 +2630,7 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector } if (uid == ResourceUID::INVALID_ID) { - uid = ResourceUID::get_singleton()->create_id(); + uid = ResourceUID::get_singleton()->create_id_for_path(file); } f->store_line("uid=\"" + ResourceUID::get_singleton()->id_to_text(uid) + "\""); // Store in readable format. @@ -2852,7 +2852,7 @@ Error EditorFileSystem::_reimport_file(const String &p_file, const HashMapcreate_id(); + uid = ResourceUID::get_singleton()->create_id_for_path(p_file); } //finally, perform import!! @@ -3541,14 +3541,14 @@ ResourceUID::ID EditorFileSystem::_resource_saver_get_resource_id_for_path(const } if (p_generate) { - return ResourceUID::get_singleton()->create_id(); // Just create a new one, we will be notified of save anyway and fetch the right UID at that time, to keep things simple. + return ResourceUID::get_singleton()->create_id_for_path(p_path); // Just create a new one, we will be notified of save anyway and fetch the right UID at that time, to keep things simple. } else { return ResourceUID::INVALID_ID; } } else if (fs->files[cpos]->uid != ResourceUID::INVALID_ID) { return fs->files[cpos]->uid; } else if (p_generate) { - return ResourceUID::get_singleton()->create_id(); // Just create a new one, we will be notified of save anyway and fetch the right UID at that time, to keep things simple. + return ResourceUID::get_singleton()->create_id_for_path(p_path); // Just create a new one, we will be notified of save anyway and fetch the right UID at that time, to keep things simple. } else { return ResourceUID::INVALID_ID; } diff --git a/editor/import/3d/resource_importer_scene.cpp b/editor/import/3d/resource_importer_scene.cpp index b05e7c2aaf2..cf2b06fb2d7 100644 --- a/editor/import/3d/resource_importer_scene.cpp +++ b/editor/import/3d/resource_importer_scene.cpp @@ -2930,7 +2930,7 @@ static Error convert_path_to_uid(ResourceUID::ID p_source_id, const String &p_ha if (ResourceUID::get_singleton()->has_id(save_id)) { if (save_path != ResourceUID::get_singleton()->get_id_path(save_id)) { // The user has specified a path which does not match the default UID. - save_id = ResourceUID::get_singleton()->create_id(); + save_id = ResourceUID::get_singleton()->create_id_for_path(save_path); } } p_settings[p_path_key] = ResourceUID::get_singleton()->id_to_text(save_id);