diff options
Diffstat (limited to 'core/io')
-rw-r--r-- | core/io/resource.cpp | 52 | ||||
-rw-r--r-- | core/io/resource.h | 13 | ||||
-rw-r--r-- | core/io/resource_format_binary.cpp | 86 | ||||
-rw-r--r-- | core/io/resource_format_binary.h | 7 |
4 files changed, 105 insertions, 53 deletions
diff --git a/core/io/resource.cpp b/core/io/resource.cpp index efa622d976..91a1386965 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -33,6 +33,7 @@ #include "core/core_string_names.h" #include "core/io/file_access.h" #include "core/io/resource_loader.h" +#include "core/math/math_funcs.h" #include "core/object/script_language.h" #include "core/os/os.h" #include "scene/main/node.h" //only so casting works @@ -94,12 +95,43 @@ String Resource::get_path() const { return path_cache; } -void Resource::set_subindex(int p_sub_index) { - subindex = p_sub_index; +String Resource::generate_scene_unique_id() { + // Generate a unique enough hash, but still user-readable. + // If it's not unique it does not matter because the saver will try again. + OS::Date date = OS::get_singleton()->get_date(); + OS::Time time = OS::get_singleton()->get_time(); + uint32_t hash = hash_djb2_one_32(OS::get_singleton()->get_ticks_usec()); + hash = hash_djb2_one_32(date.year, hash); + hash = hash_djb2_one_32(date.month, hash); + hash = hash_djb2_one_32(date.day, hash); + hash = hash_djb2_one_32(time.hour, hash); + hash = hash_djb2_one_32(time.minute, hash); + hash = hash_djb2_one_32(time.second, hash); + hash = hash_djb2_one_32(Math::rand(), hash); + + static constexpr uint32_t characters = 5; + static constexpr uint32_t char_count = ('z' - 'a'); + static constexpr uint32_t base = char_count + ('9' - '0'); + String id; + for (uint32_t i = 0; i < characters; i++) { + uint32_t c = hash % base; + if (c < char_count) { + id += String::chr('a' + c); + } else { + id += String::chr('0' + (c - char_count)); + } + hash /= base; + } + + return id; +} + +void Resource::set_scene_unique_id(const String &p_id) { + scene_unique_id = p_id; } -int Resource::get_subindex() const { - return subindex; +String Resource::get_scene_unique_id() const { + return scene_unique_id; } void Resource::set_name(const String &p_name) { @@ -350,8 +382,8 @@ bool Resource::is_translation_remapped() const { #ifdef TOOLS_ENABLED //helps keep IDs same number when loading/saving scenes. -1 clears ID and it Returns -1 when no id stored -void Resource::set_id_for_path(const String &p_path, int p_id) { - if (p_id == -1) { +void Resource::set_id_for_path(const String &p_path, const String &p_id) { + if (p_id == "") { ResourceCache::path_cache_lock.write_lock(); ResourceCache::resource_path_cache[p_path].erase(get_path()); ResourceCache::path_cache_lock.write_unlock(); @@ -362,15 +394,15 @@ void Resource::set_id_for_path(const String &p_path, int p_id) { } } -int Resource::get_id_for_path(const String &p_path) const { +String Resource::get_id_for_path(const String &p_path) const { ResourceCache::path_cache_lock.read_lock(); if (ResourceCache::resource_path_cache[p_path].has(get_path())) { - int result = ResourceCache::resource_path_cache[p_path][get_path()]; + String result = ResourceCache::resource_path_cache[p_path][get_path()]; ResourceCache::path_cache_lock.read_unlock(); return result; } else { ResourceCache::path_cache_lock.read_unlock(); - return -1; + return ""; } } #endif @@ -414,7 +446,7 @@ Resource::~Resource() { HashMap<String, Resource *> ResourceCache::resources; #ifdef TOOLS_ENABLED -HashMap<String, HashMap<String, int>> ResourceCache::resource_path_cache; +HashMap<String, HashMap<String, String>> ResourceCache::resource_path_cache; #endif RWLock ResourceCache::lock; diff --git a/core/io/resource.h b/core/io/resource.h index 028fed1c6e..0f88738f76 100644 --- a/core/io/resource.h +++ b/core/io/resource.h @@ -59,7 +59,7 @@ private: String name; String path_cache; - int subindex = 0; + String scene_unique_id; virtual bool _use_builtin_script() const { return true; } @@ -105,8 +105,9 @@ public: virtual void set_path(const String &p_path, bool p_take_over = false); String get_path() const; - void set_subindex(int p_sub_index); - int get_subindex() const; + static String generate_scene_unique_id(); + void set_scene_unique_id(const String &p_id); + String get_scene_unique_id() const; virtual Ref<Resource> duplicate(bool p_subresources = false) const; Ref<Resource> duplicate_for_local_scene(Node *p_for_scene, Map<Ref<Resource>, Ref<Resource>> &remap_cache); @@ -140,8 +141,8 @@ public: #ifdef TOOLS_ENABLED //helps keep IDs same number when loading/saving scenes. -1 clears ID and it Returns -1 when no id stored - void set_id_for_path(const String &p_path, int p_id); - int get_id_for_path(const String &p_path) const; + void set_id_for_path(const String &p_path, const String &p_id); + String get_id_for_path(const String &p_path) const; #endif Resource(); @@ -156,7 +157,7 @@ class ResourceCache { static RWLock lock; static HashMap<String, Resource *> resources; #ifdef TOOLS_ENABLED - static HashMap<String, HashMap<String, int>> resource_path_cache; // each tscn has a set of resource paths and IDs + static HashMap<String, HashMap<String, String>> resource_path_cache; // Each tscn has a set of resource paths and IDs. static RWLock path_cache_lock; #endif // TOOLS_ENABLED friend void unregister_core_types(); diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index 0e9815245f..e889586afc 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -84,9 +84,10 @@ enum { OBJECT_EXTERNAL_RESOURCE = 1, OBJECT_INTERNAL_RESOURCE = 2, OBJECT_EXTERNAL_RESOURCE_INDEX = 3, - //version 2: added 64 bits support for float and int - //version 3: changed nodepath encoding - FORMAT_VERSION = 3, + // Version 2: added 64 bits support for float and int. + // Version 3: changed nodepath encoding. + // Version 4: new string ID for ext/subresources, breaks forward compat. + FORMAT_VERSION = 4, FORMAT_VERSION_CAN_RENAME_DEPS = 1, FORMAT_VERSION_NO_NODEPATH_PROPERTY = 3, }; @@ -311,7 +312,14 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) { } break; case OBJECT_INTERNAL_RESOURCE: { uint32_t index = f->get_32(); - String path = res_path + "::" + itos(index); + String path; + + if (using_named_scene_ids) { // New format. + ERR_FAIL_INDEX_V((int)index, internal_resources.size(), ERR_PARSE_ERROR); + path = internal_resources[index].path; + } else { + path += res_path + "::" + itos(index); + } //always use internal cache for loading internal resources if (!internal_index_cache.has(path)) { @@ -320,7 +328,6 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) { } else { r_v = internal_index_cache[path]; } - } break; case OBJECT_EXTERNAL_RESOURCE: { //old file format, still around for compatibility @@ -378,7 +385,6 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) { ERR_FAIL_V(ERR_FILE_CORRUPT); } break; } - } break; case VARIANT_CALLABLE: { r_v = Callable(); @@ -659,15 +665,17 @@ Error ResourceLoaderBinary::load() { //maybe it is loaded already String path; - int subindex = 0; + String id; if (!main) { path = internal_resources[i].path; if (path.begins_with("local://")) { path = path.replace_first("local://", ""); - subindex = path.to_int(); + id = path; path = res_path + "::" + path; + + internal_resources.write[i].path = path; // Update path. } if (cache_mode == ResourceFormatLoader::CACHE_MODE_REUSE) { @@ -722,7 +730,7 @@ Error ResourceLoaderBinary::load() { if (path != String() && cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) { r->set_path(path, cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE); //if got here because the resource with same path has different type, replace it } - r->set_subindex(subindex); + r->set_scene_unique_id(id); } if (!main) { @@ -879,7 +887,11 @@ void ResourceLoaderBinary::open(FileAccess *p_f) { print_bl("type: " + type); importmd_ofs = f->get_64(); - for (int i = 0; i < 14; i++) { + uint32_t flags = f->get_32(); + if (flags & ResourceFormatSaverBinaryInstance::FORMAT_FLAG_NAMED_SCENE_IDS) { + using_named_scene_ids = true; + } + for (int i = 0; i < 13; i++) { f->get_32(); //skip a few reserved fields } @@ -1269,11 +1281,7 @@ void ResourceFormatSaverBinaryInstance::_pad_buffer(FileAccess *f, int p_bytes) } } -void ResourceFormatSaverBinaryInstance::_write_variant(const Variant &p_property, const PropertyInfo &p_hint) { - write_variant(f, p_property, resource_set, external_resources, string_map, p_hint); -} - -void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Variant &p_property, Set<RES> &resource_set, Map<RES, int> &external_resources, Map<StringName, int> &string_map, const PropertyInfo &p_hint) { +void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Variant &p_property, Map<RES, int> &resource_map, Map<RES, int> &external_resources, Map<StringName, int> &string_map, const PropertyInfo &p_hint) { switch (p_property.get_type()) { case Variant::NIL: { f->store_32(VARIANT_NIL); @@ -1492,13 +1500,13 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia f->store_32(OBJECT_EXTERNAL_RESOURCE_INDEX); f->store_32(external_resources[res]); } else { - if (!resource_set.has(res)) { + if (!resource_map.has(res)) { f->store_32(OBJECT_EMPTY); ERR_FAIL_MSG("Resource was not pre cached for the resource section, most likely due to circular reference."); } f->store_32(OBJECT_INTERNAL_RESOURCE); - f->store_32(res->get_subindex()); + f->store_32(resource_map[res]); //internal resource } @@ -1526,8 +1534,8 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia continue; */ - write_variant(f, E->get(), resource_set, external_resources, string_map); - write_variant(f, d[E->get()], resource_set, external_resources, string_map); + write_variant(f, E->get(), resource_map, external_resources, string_map); + write_variant(f, d[E->get()], resource_map, external_resources, string_map); } } break; @@ -1536,7 +1544,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia Array a = p_property; f->store_32(uint32_t(a.size())); for (int i = 0; i < a.size(); i++) { - write_variant(f, a[i], resource_set, external_resources, string_map); + write_variant(f, a[i], resource_map, external_resources, string_map); } } break; @@ -1816,7 +1824,8 @@ 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 - for (int i = 0; i < 14; i++) { + f->store_32(FORMAT_FLAG_NAMED_SCENE_IDS); + for (int i = 0; i < 13; i++) { f->store_32(0); // reserved } @@ -1886,37 +1895,43 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p // save internal resource table f->store_32(saved_resources.size()); //amount of internal resources Vector<uint64_t> ofs_pos; - Set<int> used_indices; + Set<String> used_unique_ids; for (List<RES>::Element *E = saved_resources.front(); E; E = E->next()) { RES r = E->get(); if (r->get_path() == "" || r->get_path().find("::") != -1) { - if (r->get_subindex() != 0) { - if (used_indices.has(r->get_subindex())) { - r->set_subindex(0); //repeated + if (r->get_scene_unique_id() != "") { + if (used_unique_ids.has(r->get_scene_unique_id())) { + r->set_scene_unique_id(""); } else { - used_indices.insert(r->get_subindex()); + used_unique_ids.insert(r->get_scene_unique_id()); } } } } + Map<RES, int> resource_map; + int res_index = 0; for (List<RES>::Element *E = saved_resources.front(); E; E = E->next()) { RES r = E->get(); if (r->get_path() == "" || r->get_path().find("::") != -1) { - if (r->get_subindex() == 0) { - int new_subindex = 1; - if (used_indices.size()) { - new_subindex = used_indices.back()->get() + 1; + if (r->get_scene_unique_id() == "") { + String new_id; + + while (true) { + new_id = r->get_class() + "_" + Resource::generate_scene_unique_id(); + if (!used_unique_ids.has(new_id)) { + break; + } } - r->set_subindex(new_subindex); - used_indices.insert(new_subindex); + r->set_scene_unique_id(new_id); + used_unique_ids.insert(new_id); } - save_unicode_string(f, "local://" + itos(r->get_subindex())); + save_unicode_string(f, "local://" + r->get_scene_unique_id()); if (takeover_paths) { - r->set_path(p_path + "::" + itos(r->get_subindex()), true); + r->set_path(p_path + "::" + r->get_scene_unique_id(), true); } #ifdef TOOLS_ENABLED r->set_edited(false); @@ -1926,6 +1941,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p } ofs_pos.push_back(f->get_position()); f->store_64(0); //offset in 64 bits + resource_map[r] = res_index++; } Vector<uint64_t> ofs_table; @@ -1941,7 +1957,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p for (List<Property>::Element *F = rd.properties.front(); F; F = F->next()) { Property &p = F->get(); f->store_32(p.name_idx); - _write_variant(p.value, F->get().pi); + write_variant(f, p.value, resource_map, external_resources, string_map, F->get().pi); } } diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h index abc7403935..e3dcf44492 100644 --- a/core/io/resource_format_binary.h +++ b/core/io/resource_format_binary.h @@ -60,6 +60,7 @@ class ResourceLoaderBinary { RES cache; }; + bool using_named_scene_ids = false; bool use_sub_threads = false; float *progress = nullptr; Vector<ExtResource> external_resources; @@ -150,14 +151,16 @@ class ResourceFormatSaverBinaryInstance { }; static void _pad_buffer(FileAccess *f, int p_bytes); - void _write_variant(const Variant &p_property, const PropertyInfo &p_hint = PropertyInfo()); void _find_resources(const Variant &p_variant, bool p_main = false); static void save_unicode_string(FileAccess *f, const String &p_string, bool p_bit_on_len = false); int get_string_index(const String &p_string); public: + enum { + FORMAT_FLAG_NAMED_SCENE_IDS = 1 + }; Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); - static void write_variant(FileAccess *f, const Variant &p_property, Set<RES> &resource_set, Map<RES, int> &external_resources, Map<StringName, int> &string_map, const PropertyInfo &p_hint = PropertyInfo()); + static void write_variant(FileAccess *f, const Variant &p_property, Map<RES, int> &resource_map, Map<RES, int> &external_resources, Map<StringName, int> &string_map, const PropertyInfo &p_hint = PropertyInfo()); }; class ResourceFormatSaverBinary : public ResourceFormatSaver { |