From 32b43cfeb38dc83ba8024acec32bdfc706c86a46 Mon Sep 17 00:00:00 2001 From: reduz Date: Fri, 23 Jul 2021 16:01:18 -0300 Subject: Implement Resource UIDs * Most resource types now have unique identifiers. * Applies to text, binary and imported resources. * File formats reference both by text and UID (when available). UID always has priority. * Resource UIDs are 64 bits for better compatibility with the engine. * Can be represented and used textually, example `uuid://dapwmgsmnl28u`. * A special binary cache file is used and exported, containing the mappings. Example of how it looks: ```GDScript [gd_scene load_steps=2 format=3 uid="uid://dw86wq31afig2"] [ext_resource type="PackedScene" uid="uid://bt36ojelx8q6c" path="res://subscene.scn" id="1_t56hs"] ``` GDScript, shaders and other special resource files can't currently provide UIDs, but this should be doable with special keywords on the files. This will be reserved for future PRs. --- core/io/resource_format_binary.cpp | 97 ++++++++++++++++++++++++++++++++++---- 1 file changed, 88 insertions(+), 9 deletions(-) (limited to 'core/io/resource_format_binary.cpp') diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index e889586afc..38ad541a40 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -816,13 +816,18 @@ String ResourceLoaderBinary::get_unicode_string() { } void ResourceLoaderBinary::get_dependencies(FileAccess *p_f, List *p_dependencies, bool p_add_types) { - open(p_f); + open(p_f, false, true); if (error) { return; } for (int i = 0; i < external_resources.size(); i++) { - String dep = external_resources[i].path; + String dep; + if (external_resources[i].uid != ResourceUID::INVALID_ID) { + dep = ResourceUID::get_singleton()->id_to_text(external_resources[i].uid); + } else { + dep = external_resources[i].path; + } if (p_add_types && external_resources[i].type != String()) { dep += "::" + external_resources[i].type; @@ -832,7 +837,7 @@ void ResourceLoaderBinary::get_dependencies(FileAccess *p_f, List *p_dep } } -void ResourceLoaderBinary::open(FileAccess *p_f) { +void ResourceLoaderBinary::open(FileAccess *p_f, bool p_no_resources, bool p_keep_uuid_paths) { error = OK; f = p_f; @@ -891,10 +896,24 @@ void ResourceLoaderBinary::open(FileAccess *p_f) { if (flags & ResourceFormatSaverBinaryInstance::FORMAT_FLAG_NAMED_SCENE_IDS) { using_named_scene_ids = true; } - for (int i = 0; i < 13; i++) { + if (flags & ResourceFormatSaverBinaryInstance::FORMAT_FLAG_UIDS) { + using_uids = true; + } + + if (using_uids) { + uid = f->get_64(); + } else { + uid = ResourceUID::INVALID_ID; + } + + for (int i = 0; i < 5; i++) { f->get_32(); //skip a few reserved fields } + if (p_no_resources) { + return; + } + uint32_t string_table_size = f->get_32(); string_map.resize(string_table_size); for (uint32_t i = 0; i < string_table_size; i++) { @@ -908,8 +927,18 @@ void ResourceLoaderBinary::open(FileAccess *p_f) { for (uint32_t i = 0; i < ext_resources_size; i++) { ExtResource er; er.type = get_unicode_string(); - er.path = get_unicode_string(); + if (using_uids) { + er.uid = f->get_64(); + if (!p_keep_uuid_paths && er.uid != ResourceUID::INVALID_ID) { + if (ResourceUID::get_singleton()->has_id(er.uid)) { + // If a UID is found and the path is valid, it will be used, otherwise, it falls back to the path. + er.path = ResourceUID::get_singleton()->get_id_path(er.uid); + } else { + WARN_PRINT(String(res_path + ": In external resouce #" + itos(i) + ", invalid UUID: " + ResourceUID::get_singleton()->id_to_text(er.uid) + " - using text path instead: " + er.path).utf8().get_data()); + } + } + } external_resources.push_back(er); } @@ -1173,8 +1202,15 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons uint64_t importmd_ofs = f->get_64(); fw->store_64(0); //metadata offset - for (int i = 0; i < 14; i++) { - fw->store_32(0); + uint32_t flags = f->get_32(); + bool using_uids = (flags & ResourceFormatSaverBinaryInstance::FORMAT_FLAG_UIDS); + uint64_t uid_data = f->get_64(); + + fw->store_32(flags); + fw->store_64(uid_data); + + for (int i = 0; i < 5; i++) { + f->store_32(0); // reserved f->get_32(); } @@ -1195,6 +1231,16 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons String type = get_ustring(f); String path = get_ustring(f); + if (using_uids) { + ResourceUID::ID uid = f->get_64(); + if (uid != ResourceUID::INVALID_ID) { + if (ResourceUID::get_singleton()->has_id(uid)) { + // If a UID is found and the path is valid, it will be used, otherwise, it falls back to the path. + path = ResourceUID::get_singleton()->get_id_path(uid); + } + } + } + bool relative = false; if (!path.begins_with("res://")) { path = local_path.plus_file(path).simplify_path(); @@ -1206,6 +1252,8 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons path = np; } + String full_path = path; + if (relative) { //restore relative path = local_path.path_to_file(path); @@ -1213,6 +1261,11 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons save_ustring(fw, type); save_ustring(fw, path); + + if (using_uids) { + ResourceUID::ID uid = ResourceSaver::get_resource_id_for_path(full_path); + f->store_64(uid); + } } int64_t size_diff = (int64_t)fw->get_position() - (int64_t)f->get_position(); @@ -1268,6 +1321,28 @@ String ResourceFormatLoaderBinary::get_resource_type(const String &p_path) const return ClassDB::get_compatibility_remapped_class(r); } +ResourceUID::ID ResourceFormatLoaderBinary::get_resource_uid(const String &p_path) const { + String ext = p_path.get_extension().to_lower(); + if (!ClassDB::is_resource_extension(ext)) { + return ResourceUID::INVALID_ID; + } + + FileAccess *f = FileAccess::open(p_path, FileAccess::READ); + if (!f) { + return ResourceUID::INVALID_ID; //could not read + } + + ResourceLoaderBinary loader; + loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path); + loader.res_path = loader.local_path; + //loader.set_local_path( Globals::get_singleton()->localize_path(p_path) ); + loader.open(f, true); + if (loader.error != OK) { + return ResourceUID::INVALID_ID; //could not read + } + return loader.uid; +} + /////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////// @@ -1824,8 +1899,10 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p save_unicode_string(f, p_resource->get_class()); f->store_64(0); //offset to import metadata - f->store_32(FORMAT_FLAG_NAMED_SCENE_IDS); - for (int i = 0; i < 13; i++) { + f->store_32(FORMAT_FLAG_NAMED_SCENE_IDS | FORMAT_FLAG_UIDS); + ResourceUID::ID uid = ResourceSaver::get_resource_id_for_path(p_path, true); + f->store_64(uid); + for (int i = 0; i < 5; i++) { f->store_32(0); // reserved } @@ -1891,6 +1968,8 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p String path = save_order[i]->get_path(); path = relative_paths ? local_path.path_to_file(path) : path; save_unicode_string(f, path); + ResourceUID::ID ruid = ResourceSaver::get_resource_id_for_path(save_order[i]->get_path(), false); + f->store_64(ruid); } // save internal resource table f->store_32(saved_resources.size()); //amount of internal resources -- cgit v1.2.3