mirror of
https://github.com/godotengine/godot
synced 2024-09-04 21:58:28 +00:00
Merge pull request #50786 from reduz/implement-resource-uids
Implement Resource UIDs
This commit is contained in:
commit
2b1e6e303e
|
@ -31,6 +31,7 @@
|
|||
#ifndef RESOURCE_H
|
||||
#define RESOURCE_H
|
||||
|
||||
#include "core/io/resource_uid.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "core/object/ref_counted.h"
|
||||
#include "core/templates/safe_refcount.h"
|
||||
|
|
|
@ -816,13 +816,18 @@ String ResourceLoaderBinary::get_unicode_string() {
|
|||
}
|
||||
|
||||
void ResourceLoaderBinary::get_dependencies(FileAccess *p_f, List<String> *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<String> *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
|
||||
|
|
|
@ -47,6 +47,8 @@ class ResourceLoaderBinary {
|
|||
|
||||
uint64_t importmd_ofs = 0;
|
||||
|
||||
ResourceUID::ID uid = ResourceUID::INVALID_ID;
|
||||
|
||||
Vector<char> str_buf;
|
||||
List<RES> resource_cache;
|
||||
|
||||
|
@ -57,10 +59,12 @@ class ResourceLoaderBinary {
|
|||
struct ExtResource {
|
||||
String path;
|
||||
String type;
|
||||
ResourceUID::ID uid = ResourceUID::INVALID_ID;
|
||||
RES cache;
|
||||
};
|
||||
|
||||
bool using_named_scene_ids = false;
|
||||
bool using_uids = false;
|
||||
bool use_sub_threads = false;
|
||||
float *progress = nullptr;
|
||||
Vector<ExtResource> external_resources;
|
||||
|
@ -94,7 +98,7 @@ public:
|
|||
void set_translation_remapped(bool p_remapped);
|
||||
|
||||
void set_remaps(const Map<String, String> &p_remaps) { remaps = p_remaps; }
|
||||
void open(FileAccess *p_f);
|
||||
void open(FileAccess *p_f, bool p_no_resources = false, bool p_keep_uuid_paths = false);
|
||||
String recognize(FileAccess *p_f);
|
||||
void get_dependencies(FileAccess *p_f, List<String> *p_dependencies, bool p_add_types);
|
||||
|
||||
|
@ -109,6 +113,7 @@ public:
|
|||
virtual void get_recognized_extensions(List<String> *p_extensions) const;
|
||||
virtual bool handles_type(const String &p_type) const;
|
||||
virtual String get_resource_type(const String &p_path) const;
|
||||
virtual ResourceUID::ID get_resource_uid(const String &p_path) const;
|
||||
virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false);
|
||||
virtual Error rename_dependencies(const String &p_path, const Map<String, String> &p_map);
|
||||
};
|
||||
|
@ -157,7 +162,8 @@ class ResourceFormatSaverBinaryInstance {
|
|||
|
||||
public:
|
||||
enum {
|
||||
FORMAT_FLAG_NAMED_SCENE_IDS = 1
|
||||
FORMAT_FLAG_NAMED_SCENE_IDS = 1,
|
||||
FORMAT_FLAG_UIDS = 2,
|
||||
};
|
||||
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, Map<RES, int> &resource_map, Map<RES, int> &external_resources, Map<StringName, int> &string_map, const PropertyInfo &p_hint = PropertyInfo());
|
||||
|
|
|
@ -93,6 +93,8 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy
|
|||
r_path_and_type.type = ClassDB::get_compatibility_remapped_class(value);
|
||||
} else if (assign == "importer") {
|
||||
r_path_and_type.importer = value;
|
||||
} else if (assign == "uid") {
|
||||
r_path_and_type.uid = ResourceUID::get_singleton()->text_to_id(value);
|
||||
} else if (assign == "group_file") {
|
||||
r_path_and_type.group_file = value;
|
||||
} else if (assign == "metadata") {
|
||||
|
@ -336,6 +338,17 @@ String ResourceFormatImporter::get_resource_type(const String &p_path) const {
|
|||
return pat.type;
|
||||
}
|
||||
|
||||
ResourceUID::ID ResourceFormatImporter::get_resource_uid(const String &p_path) const {
|
||||
PathAndType pat;
|
||||
Error err = _get_path_and_type(p_path, pat);
|
||||
|
||||
if (err != OK) {
|
||||
return ResourceUID::INVALID_ID;
|
||||
}
|
||||
|
||||
return pat.uid;
|
||||
}
|
||||
|
||||
Variant ResourceFormatImporter::get_resource_metadata(const String &p_path) const {
|
||||
PathAndType pat;
|
||||
Error err = _get_path_and_type(p_path, pat);
|
||||
|
|
|
@ -42,6 +42,7 @@ class ResourceFormatImporter : public ResourceFormatLoader {
|
|||
String importer;
|
||||
String group_file;
|
||||
Variant metadata;
|
||||
uint64_t uid = ResourceUID::INVALID_ID;
|
||||
};
|
||||
|
||||
Error _get_path_and_type(const String &p_path, PathAndType &r_path_and_type, bool *r_valid = nullptr) const;
|
||||
|
@ -63,6 +64,8 @@ public:
|
|||
virtual bool recognize_path(const String &p_path, const String &p_for_type = String()) const;
|
||||
virtual bool handles_type(const String &p_type) const;
|
||||
virtual String get_resource_type(const String &p_path) const;
|
||||
virtual ResourceUID::ID get_resource_uid(const String &p_path) const;
|
||||
|
||||
virtual Variant get_resource_metadata(const String &p_path) const;
|
||||
virtual bool is_import_valid(const String &p_path) const;
|
||||
virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false);
|
||||
|
|
|
@ -84,6 +84,14 @@ String ResourceFormatLoader::get_resource_type(const String &p_path) const {
|
|||
return "";
|
||||
}
|
||||
|
||||
ResourceUID::ID ResourceFormatLoader::get_resource_uid(const String &p_path) const {
|
||||
if (get_script_instance() && get_script_instance()->has_method("_get_resource_uid")) {
|
||||
return get_script_instance()->call("_get_resource_uid", p_path);
|
||||
}
|
||||
|
||||
return ResourceUID::INVALID_ID;
|
||||
}
|
||||
|
||||
void ResourceFormatLoader::get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const {
|
||||
if (p_type == "" || handles_type(p_type)) {
|
||||
get_recognized_extensions(p_extensions);
|
||||
|
@ -270,13 +278,18 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
|
|||
thread_load_mutex->unlock();
|
||||
}
|
||||
|
||||
Error ResourceLoader::load_threaded_request(const String &p_path, const String &p_type_hint, bool p_use_sub_threads, ResourceFormatLoader::CacheMode p_cache_mode, const String &p_source_resource) {
|
||||
String local_path;
|
||||
if (p_path.is_rel_path()) {
|
||||
local_path = "res://" + p_path;
|
||||
static String _validate_local_path(const String &p_path) {
|
||||
ResourceUID::ID uid = ResourceUID::get_singleton()->text_to_id(p_path);
|
||||
if (uid != ResourceUID::INVALID_ID) {
|
||||
return ResourceUID::get_singleton()->get_id_path(uid);
|
||||
} else if (p_path.is_rel_path()) {
|
||||
return "res://" + p_path;
|
||||
} else {
|
||||
local_path = ProjectSettings::get_singleton()->localize_path(p_path);
|
||||
return ProjectSettings::get_singleton()->localize_path(p_path);
|
||||
}
|
||||
}
|
||||
Error ResourceLoader::load_threaded_request(const String &p_path, const String &p_type_hint, bool p_use_sub_threads, ResourceFormatLoader::CacheMode p_cache_mode, const String &p_source_resource) {
|
||||
String local_path = _validate_local_path(p_path);
|
||||
|
||||
thread_load_mutex->lock();
|
||||
|
||||
|
@ -399,12 +412,7 @@ float ResourceLoader::_dependency_get_progress(const String &p_path) {
|
|||
}
|
||||
|
||||
ResourceLoader::ThreadLoadStatus ResourceLoader::load_threaded_get_status(const String &p_path, float *r_progress) {
|
||||
String local_path;
|
||||
if (p_path.is_rel_path()) {
|
||||
local_path = "res://" + p_path;
|
||||
} else {
|
||||
local_path = ProjectSettings::get_singleton()->localize_path(p_path);
|
||||
}
|
||||
String local_path = _validate_local_path(p_path);
|
||||
|
||||
thread_load_mutex->lock();
|
||||
if (!thread_load_tasks.has(local_path)) {
|
||||
|
@ -424,12 +432,7 @@ ResourceLoader::ThreadLoadStatus ResourceLoader::load_threaded_get_status(const
|
|||
}
|
||||
|
||||
RES ResourceLoader::load_threaded_get(const String &p_path, Error *r_error) {
|
||||
String local_path;
|
||||
if (p_path.is_rel_path()) {
|
||||
local_path = "res://" + p_path;
|
||||
} else {
|
||||
local_path = ProjectSettings::get_singleton()->localize_path(p_path);
|
||||
}
|
||||
String local_path = _validate_local_path(p_path);
|
||||
|
||||
thread_load_mutex->lock();
|
||||
if (!thread_load_tasks.has(local_path)) {
|
||||
|
@ -510,12 +513,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, Resour
|
|||
*r_error = ERR_CANT_OPEN;
|
||||
}
|
||||
|
||||
String local_path;
|
||||
if (p_path.is_rel_path()) {
|
||||
local_path = "res://" + p_path;
|
||||
} else {
|
||||
local_path = ProjectSettings::get_singleton()->localize_path(p_path);
|
||||
}
|
||||
String local_path = _validate_local_path(p_path);
|
||||
|
||||
if (p_cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
|
||||
thread_load_mutex->lock();
|
||||
|
@ -612,12 +610,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, Resour
|
|||
}
|
||||
|
||||
bool ResourceLoader::exists(const String &p_path, const String &p_type_hint) {
|
||||
String local_path;
|
||||
if (p_path.is_rel_path()) {
|
||||
local_path = "res://" + p_path;
|
||||
} else {
|
||||
local_path = ProjectSettings::get_singleton()->localize_path(p_path);
|
||||
}
|
||||
String local_path = _validate_local_path(p_path);
|
||||
|
||||
if (ResourceCache::has(local_path)) {
|
||||
return true; // If cached, it probably exists
|
||||
|
@ -677,14 +670,7 @@ void ResourceLoader::remove_resource_format_loader(Ref<ResourceFormatLoader> p_f
|
|||
}
|
||||
|
||||
int ResourceLoader::get_import_order(const String &p_path) {
|
||||
String path = _path_remap(p_path);
|
||||
|
||||
String local_path;
|
||||
if (path.is_rel_path()) {
|
||||
local_path = "res://" + path;
|
||||
} else {
|
||||
local_path = ProjectSettings::get_singleton()->localize_path(path);
|
||||
}
|
||||
String local_path = _path_remap(_validate_local_path(p_path));
|
||||
|
||||
for (int i = 0; i < loader_count; i++) {
|
||||
if (!loader[i]->recognize_path(local_path)) {
|
||||
|
@ -702,14 +688,7 @@ int ResourceLoader::get_import_order(const String &p_path) {
|
|||
}
|
||||
|
||||
String ResourceLoader::get_import_group_file(const String &p_path) {
|
||||
String path = _path_remap(p_path);
|
||||
|
||||
String local_path;
|
||||
if (path.is_rel_path()) {
|
||||
local_path = "res://" + path;
|
||||
} else {
|
||||
local_path = ProjectSettings::get_singleton()->localize_path(path);
|
||||
}
|
||||
String local_path = _path_remap(_validate_local_path(p_path));
|
||||
|
||||
for (int i = 0; i < loader_count; i++) {
|
||||
if (!loader[i]->recognize_path(local_path)) {
|
||||
|
@ -727,14 +706,7 @@ String ResourceLoader::get_import_group_file(const String &p_path) {
|
|||
}
|
||||
|
||||
bool ResourceLoader::is_import_valid(const String &p_path) {
|
||||
String path = _path_remap(p_path);
|
||||
|
||||
String local_path;
|
||||
if (path.is_rel_path()) {
|
||||
local_path = "res://" + path;
|
||||
} else {
|
||||
local_path = ProjectSettings::get_singleton()->localize_path(path);
|
||||
}
|
||||
String local_path = _path_remap(_validate_local_path(p_path));
|
||||
|
||||
for (int i = 0; i < loader_count; i++) {
|
||||
if (!loader[i]->recognize_path(local_path)) {
|
||||
|
@ -752,14 +724,7 @@ bool ResourceLoader::is_import_valid(const String &p_path) {
|
|||
}
|
||||
|
||||
bool ResourceLoader::is_imported(const String &p_path) {
|
||||
String path = _path_remap(p_path);
|
||||
|
||||
String local_path;
|
||||
if (path.is_rel_path()) {
|
||||
local_path = "res://" + path;
|
||||
} else {
|
||||
local_path = ProjectSettings::get_singleton()->localize_path(path);
|
||||
}
|
||||
String local_path = _path_remap(_validate_local_path(p_path));
|
||||
|
||||
for (int i = 0; i < loader_count; i++) {
|
||||
if (!loader[i]->recognize_path(local_path)) {
|
||||
|
@ -777,14 +742,7 @@ bool ResourceLoader::is_imported(const String &p_path) {
|
|||
}
|
||||
|
||||
void ResourceLoader::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) {
|
||||
String path = _path_remap(p_path);
|
||||
|
||||
String local_path;
|
||||
if (path.is_rel_path()) {
|
||||
local_path = "res://" + path;
|
||||
} else {
|
||||
local_path = ProjectSettings::get_singleton()->localize_path(path);
|
||||
}
|
||||
String local_path = _path_remap(_validate_local_path(p_path));
|
||||
|
||||
for (int i = 0; i < loader_count; i++) {
|
||||
if (!loader[i]->recognize_path(local_path)) {
|
||||
|
@ -800,14 +758,7 @@ void ResourceLoader::get_dependencies(const String &p_path, List<String> *p_depe
|
|||
}
|
||||
|
||||
Error ResourceLoader::rename_dependencies(const String &p_path, const Map<String, String> &p_map) {
|
||||
String path = _path_remap(p_path);
|
||||
|
||||
String local_path;
|
||||
if (path.is_rel_path()) {
|
||||
local_path = "res://" + path;
|
||||
} else {
|
||||
local_path = ProjectSettings::get_singleton()->localize_path(path);
|
||||
}
|
||||
String local_path = _path_remap(_validate_local_path(p_path));
|
||||
|
||||
for (int i = 0; i < loader_count; i++) {
|
||||
if (!loader[i]->recognize_path(local_path)) {
|
||||
|
@ -825,12 +776,7 @@ Error ResourceLoader::rename_dependencies(const String &p_path, const Map<String
|
|||
}
|
||||
|
||||
String ResourceLoader::get_resource_type(const String &p_path) {
|
||||
String local_path;
|
||||
if (p_path.is_rel_path()) {
|
||||
local_path = "res://" + p_path;
|
||||
} else {
|
||||
local_path = ProjectSettings::get_singleton()->localize_path(p_path);
|
||||
}
|
||||
String local_path = _validate_local_path(p_path);
|
||||
|
||||
for (int i = 0; i < loader_count; i++) {
|
||||
String result = loader[i]->get_resource_type(local_path);
|
||||
|
@ -842,6 +788,19 @@ String ResourceLoader::get_resource_type(const String &p_path) {
|
|||
return "";
|
||||
}
|
||||
|
||||
ResourceUID::ID ResourceLoader::get_resource_uid(const String &p_path) {
|
||||
String local_path = _validate_local_path(p_path);
|
||||
|
||||
for (int i = 0; i < loader_count; i++) {
|
||||
ResourceUID::ID id = loader[i]->get_resource_uid(local_path);
|
||||
if (id != ResourceUID::INVALID_ID) {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
return ResourceUID::INVALID_ID;
|
||||
}
|
||||
|
||||
String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_remapped) {
|
||||
String new_path = p_path;
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ public:
|
|||
virtual bool recognize_path(const String &p_path, const String &p_for_type = String()) const;
|
||||
virtual bool handles_type(const String &p_type) const;
|
||||
virtual String get_resource_type(const String &p_path) const;
|
||||
virtual ResourceUID::ID get_resource_uid(const String &p_path) const;
|
||||
virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false);
|
||||
virtual Error rename_dependencies(const String &p_path, const Map<String, String> &p_map);
|
||||
virtual bool is_import_valid(const String &p_path) const { return true; }
|
||||
|
@ -157,6 +158,7 @@ public:
|
|||
static void add_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader, bool p_at_front = false);
|
||||
static void remove_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader);
|
||||
static String get_resource_type(const String &p_path);
|
||||
static ResourceUID::ID get_resource_uid(const String &p_path);
|
||||
static void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false);
|
||||
static Error rename_dependencies(const String &p_path, const Map<String, String> &p_map);
|
||||
static bool is_import_valid(const String &p_path);
|
||||
|
|
|
@ -39,6 +39,7 @@ Ref<ResourceFormatSaver> ResourceSaver::saver[MAX_SAVERS];
|
|||
int ResourceSaver::saver_count = 0;
|
||||
bool ResourceSaver::timestamp_on_save = false;
|
||||
ResourceSavedCallback ResourceSaver::save_callback = nullptr;
|
||||
ResourceSaverGetResourceIDForPath ResourceSaver::save_get_id_for_path = nullptr;
|
||||
|
||||
Error ResourceFormatSaver::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
|
||||
if (get_script_instance() && get_script_instance()->has_method("_save")) {
|
||||
|
@ -258,3 +259,14 @@ void ResourceSaver::remove_custom_savers() {
|
|||
remove_resource_format_saver(custom_savers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
ResourceUID::ID ResourceSaver::get_resource_id_for_path(const String &p_path, bool p_generate) {
|
||||
if (save_get_id_for_path) {
|
||||
return save_get_id_for_path(p_path, p_generate);
|
||||
}
|
||||
return ResourceUID::INVALID_ID;
|
||||
}
|
||||
|
||||
void ResourceSaver::set_get_resource_id_for_path(ResourceSaverGetResourceIDForPath p_callback) {
|
||||
save_get_id_for_path = p_callback;
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ public:
|
|||
};
|
||||
|
||||
typedef void (*ResourceSavedCallback)(Ref<Resource> p_resource, const String &p_path);
|
||||
typedef ResourceUID::ID (*ResourceSaverGetResourceIDForPath)(const String &p_path, bool p_generate);
|
||||
|
||||
class ResourceSaver {
|
||||
enum {
|
||||
|
@ -58,6 +59,7 @@ class ResourceSaver {
|
|||
static int saver_count;
|
||||
static bool timestamp_on_save;
|
||||
static ResourceSavedCallback save_callback;
|
||||
static ResourceSaverGetResourceIDForPath save_get_id_for_path;
|
||||
|
||||
static Ref<ResourceFormatSaver> _find_custom_resource_format_saver(String path);
|
||||
|
||||
|
@ -80,7 +82,10 @@ public:
|
|||
static void set_timestamp_on_save(bool p_timestamp) { timestamp_on_save = p_timestamp; }
|
||||
static bool get_timestamp_on_save() { return timestamp_on_save; }
|
||||
|
||||
static ResourceUID::ID get_resource_id_for_path(const String &p_path, bool p_generate = false);
|
||||
|
||||
static void set_save_callback(ResourceSavedCallback p_callback);
|
||||
static void set_get_resource_id_for_path(ResourceSaverGetResourceIDForPath p_callback);
|
||||
|
||||
static bool add_custom_resource_format_saver(String script_path);
|
||||
static void remove_custom_resource_format_saver(String script_path);
|
||||
|
|
262
core/io/resource_uid.cpp
Normal file
262
core/io/resource_uid.cpp
Normal file
|
@ -0,0 +1,262 @@
|
|||
/*************************************************************************/
|
||||
/* resource_uid.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "resource_uid.h"
|
||||
#include "core/crypto/crypto.h"
|
||||
#include "core/io/dir_access.h"
|
||||
#include "core/io/file_access.h"
|
||||
|
||||
static constexpr uint32_t char_count = ('z' - 'a');
|
||||
static constexpr uint32_t base = char_count + ('9' - '0');
|
||||
|
||||
const char *ResourceUID::CACHE_FILE = "res://.godot/uid_cache.bin";
|
||||
|
||||
String ResourceUID::id_to_text(ID p_id) const {
|
||||
if (p_id < 0) {
|
||||
return "uid://<invalid>";
|
||||
}
|
||||
String txt;
|
||||
|
||||
while (p_id) {
|
||||
uint32_t c = p_id % base;
|
||||
if (c < char_count) {
|
||||
txt = String::chr('a' + c) + txt;
|
||||
} else {
|
||||
txt = String::chr('0' + (c - char_count)) + txt;
|
||||
}
|
||||
p_id /= base;
|
||||
}
|
||||
|
||||
return "uid://" + txt;
|
||||
}
|
||||
|
||||
ResourceUID::ID ResourceUID::text_to_id(const String &p_text) const {
|
||||
if (!p_text.begins_with("uid://") || p_text == "uid://<invalid>") {
|
||||
return INVALID_ID;
|
||||
}
|
||||
|
||||
uint32_t l = p_text.length();
|
||||
uint64_t uid = 0;
|
||||
for (uint32_t i = 6; i < l; i++) {
|
||||
uid *= base;
|
||||
uint32_t c = p_text[i];
|
||||
if (c >= 'a' && c <= 'z') {
|
||||
uid += c - 'a';
|
||||
} else if (c >= '0' && c <= '9') {
|
||||
uid += c - '0' + char_count;
|
||||
} else {
|
||||
return INVALID_ID;
|
||||
}
|
||||
}
|
||||
return ID(uid & 0x7FFFFFFFFFFFFFFF);
|
||||
}
|
||||
|
||||
ResourceUID::ID ResourceUID::create_id() const {
|
||||
mutex.lock();
|
||||
if (crypto.is_null()) {
|
||||
crypto = Ref<Crypto>(Crypto::create());
|
||||
}
|
||||
mutex.unlock();
|
||||
while (true) {
|
||||
PackedByteArray bytes = crypto->generate_random_bytes(8);
|
||||
ERR_FAIL_COND_V(bytes.size() != 8, INVALID_ID);
|
||||
const uint64_t *ptr64 = (const uint64_t *)bytes.ptr();
|
||||
ID id = int64_t((*ptr64) & 0x7FFFFFFFFFFFFFFF);
|
||||
mutex.lock();
|
||||
bool exists = unique_ids.has(id);
|
||||
mutex.unlock();
|
||||
if (!exists) {
|
||||
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));
|
||||
Cache c;
|
||||
c.cs = p_path.utf8();
|
||||
unique_ids[p_id] = c;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
void ResourceUID::set_id(ID p_id, const String &p_path) {
|
||||
MutexLock l(mutex);
|
||||
ERR_FAIL_COND(!unique_ids.has(p_id));
|
||||
CharString cs = p_path.utf8();
|
||||
if (strcmp(cs.ptr(), unique_ids[p_id].cs.ptr()) != 0) {
|
||||
unique_ids[p_id].cs = cs;
|
||||
unique_ids[p_id].saved_to_cache = false; //changed
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
String ResourceUID::get_id_path(ID p_id) const {
|
||||
MutexLock l(mutex);
|
||||
ERR_FAIL_COND_V(!unique_ids.has(p_id), String());
|
||||
const CharString &cs = unique_ids[p_id].cs;
|
||||
String s(cs.ptr());
|
||||
return s;
|
||||
}
|
||||
void ResourceUID::remove_id(ID p_id) {
|
||||
MutexLock l(mutex);
|
||||
ERR_FAIL_COND(!unique_ids.has(p_id));
|
||||
unique_ids.erase(p_id);
|
||||
}
|
||||
|
||||
Error ResourceUID::save_to_cache() {
|
||||
if (!FileAccess::exists(CACHE_FILE)) {
|
||||
DirAccessRef d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
||||
d->make_dir_recursive(String(CACHE_FILE).get_base_dir()); //ensure base dir exists
|
||||
}
|
||||
|
||||
FileAccessRef f = FileAccess::open(CACHE_FILE, FileAccess::WRITE);
|
||||
if (!f) {
|
||||
return ERR_CANT_OPEN;
|
||||
}
|
||||
|
||||
MutexLock l(mutex);
|
||||
f->store_32(unique_ids.size());
|
||||
|
||||
cache_entries = 0;
|
||||
|
||||
for (OrderedHashMap<ID, Cache>::Element E = unique_ids.front(); E; E = E.next()) {
|
||||
f->store_64(E.key());
|
||||
uint32_t s = E.get().cs.length();
|
||||
f->store_32(s);
|
||||
f->store_buffer((const uint8_t *)E.get().cs.ptr(), s);
|
||||
E.get().saved_to_cache = true;
|
||||
cache_entries++;
|
||||
}
|
||||
|
||||
changed = false;
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error ResourceUID::load_from_cache() {
|
||||
FileAccessRef f = FileAccess::open(CACHE_FILE, FileAccess::READ);
|
||||
if (!f) {
|
||||
return ERR_CANT_OPEN;
|
||||
}
|
||||
|
||||
MutexLock l(mutex);
|
||||
unique_ids.clear();
|
||||
|
||||
uint32_t entry_count = f->get_32();
|
||||
for (uint32_t i = 0; i < entry_count; i++) {
|
||||
int64_t id = f->get_64();
|
||||
int32_t len = f->get_32();
|
||||
Cache c;
|
||||
c.cs.resize(len + 1);
|
||||
ERR_FAIL_COND_V(c.cs.size() != len + 1, ERR_FILE_CORRUPT); // out of memory
|
||||
c.cs[len] = 0;
|
||||
int32_t rl = f->get_buffer((uint8_t *)c.cs.ptrw(), len);
|
||||
ERR_FAIL_COND_V(rl != len, ERR_FILE_CORRUPT);
|
||||
|
||||
c.saved_to_cache = true;
|
||||
unique_ids[id] = c;
|
||||
}
|
||||
|
||||
cache_entries = entry_count;
|
||||
changed = false;
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error ResourceUID::update_cache() {
|
||||
if (!changed) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
if (cache_entries == 0) {
|
||||
return save_to_cache();
|
||||
}
|
||||
MutexLock l(mutex);
|
||||
|
||||
FileAccess *f = nullptr;
|
||||
for (OrderedHashMap<ID, Cache>::Element E = unique_ids.front(); E; E = E.next()) {
|
||||
if (!E.get().saved_to_cache) {
|
||||
if (f == nullptr) {
|
||||
f = FileAccess::open(CACHE_FILE, FileAccess::READ_WRITE); //append
|
||||
if (!f) {
|
||||
return ERR_CANT_OPEN;
|
||||
}
|
||||
f->seek_end();
|
||||
}
|
||||
f->store_64(E.key());
|
||||
uint32_t s = E.get().cs.length();
|
||||
f->store_32(s);
|
||||
f->store_buffer((const uint8_t *)E.get().cs.ptr(), s);
|
||||
E.get().saved_to_cache = true;
|
||||
cache_entries++;
|
||||
}
|
||||
}
|
||||
|
||||
if (f != nullptr) {
|
||||
f->seek(0);
|
||||
f->store_32(cache_entries); //update amount of entries
|
||||
f->close();
|
||||
memdelete(f);
|
||||
}
|
||||
|
||||
changed = false;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void ResourceUID::clear() {
|
||||
cache_entries = 0;
|
||||
unique_ids.clear();
|
||||
changed = false;
|
||||
}
|
||||
void ResourceUID::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("id_to_text", "id"), &ResourceUID::id_to_text);
|
||||
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("has_id", "id"), &ResourceUID::has_id);
|
||||
ClassDB::bind_method(D_METHOD("add_id", "id", "path"), &ResourceUID::add_id);
|
||||
ClassDB::bind_method(D_METHOD("set_id", "id", "path"), &ResourceUID::set_id);
|
||||
ClassDB::bind_method(D_METHOD("get_id_path", "id"), &ResourceUID::get_id_path);
|
||||
ClassDB::bind_method(D_METHOD("remove_id", "id", "path"), &ResourceUID::remove_id);
|
||||
|
||||
BIND_CONSTANT(INVALID_ID)
|
||||
}
|
||||
ResourceUID *ResourceUID::singleton = nullptr;
|
||||
ResourceUID::ResourceUID() {
|
||||
ERR_FAIL_COND(singleton != nullptr);
|
||||
singleton = this;
|
||||
}
|
||||
ResourceUID::~ResourceUID() {
|
||||
}
|
89
core/io/resource_uid.h
Normal file
89
core/io/resource_uid.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*************************************************************************/
|
||||
/* resource_uid.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef RESOURCE_UUID_H
|
||||
#define RESOURCE_UUID_H
|
||||
|
||||
#include "core/object/ref_counted.h"
|
||||
#include "core/string/string_name.h"
|
||||
#include "core/templates/ordered_hash_map.h"
|
||||
|
||||
class Crypto;
|
||||
class ResourceUID : public Object {
|
||||
GDCLASS(ResourceUID, Object)
|
||||
public:
|
||||
typedef int64_t ID;
|
||||
enum {
|
||||
INVALID_ID = -1
|
||||
};
|
||||
|
||||
static const char *CACHE_FILE;
|
||||
|
||||
private:
|
||||
mutable Ref<Crypto> crypto;
|
||||
Mutex mutex;
|
||||
struct Cache {
|
||||
CharString cs;
|
||||
bool saved_to_cache = false;
|
||||
};
|
||||
|
||||
OrderedHashMap<ID, Cache> unique_ids; //unique IDs and utf8 paths (less memory used)
|
||||
static ResourceUID *singleton;
|
||||
|
||||
uint32_t cache_entries = 0;
|
||||
bool changed = false;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
String id_to_text(ID p_id) const;
|
||||
ID text_to_id(const String &p_text) const;
|
||||
|
||||
ID create_id() const;
|
||||
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);
|
||||
String get_id_path(ID p_id) const;
|
||||
void remove_id(ID p_id);
|
||||
|
||||
Error load_from_cache();
|
||||
Error save_to_cache();
|
||||
Error update_cache();
|
||||
|
||||
void clear();
|
||||
|
||||
static ResourceUID *get_singleton() { return singleton; }
|
||||
|
||||
ResourceUID();
|
||||
~ResourceUID();
|
||||
};
|
||||
|
||||
#endif // RESOURCEUUID_H
|
|
@ -1495,6 +1495,10 @@ void ClassDB::get_resource_base_extensions(List<String> *p_extensions) {
|
|||
}
|
||||
}
|
||||
|
||||
bool ClassDB::is_resource_extension(const StringName &p_extension) {
|
||||
return resource_base_extensions.has(p_extension);
|
||||
}
|
||||
|
||||
void ClassDB::get_extensions_for_type(const StringName &p_class, List<String> *p_extensions) {
|
||||
const StringName *K = nullptr;
|
||||
|
||||
|
|
|
@ -396,6 +396,7 @@ public:
|
|||
static void add_resource_base_extension(const StringName &p_extension, const StringName &p_class);
|
||||
static void get_resource_base_extensions(List<String> *p_extensions);
|
||||
static void get_extensions_for_type(const StringName &p_class, List<String> *p_extensions);
|
||||
static bool is_resource_extension(const StringName &p_extension);
|
||||
|
||||
static void add_compatibility_class(const StringName &p_class, const StringName &p_fallback);
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#include "core/io/pck_packer.h"
|
||||
#include "core/io/resource_format_binary.h"
|
||||
#include "core/io/resource_importer.h"
|
||||
#include "core/io/resource_uid.h"
|
||||
#include "core/io/stream_peer_ssl.h"
|
||||
#include "core/io/tcp_server.h"
|
||||
#include "core/io/translation_loader_po.h"
|
||||
|
@ -102,6 +103,8 @@ static NativeExtensionManager *native_extension_manager = nullptr;
|
|||
extern void register_global_constants();
|
||||
extern void unregister_global_constants();
|
||||
|
||||
static ResourceUID *resource_uid = nullptr;
|
||||
|
||||
void register_core_types() {
|
||||
//consistency check
|
||||
static_assert(sizeof(Callable) <= 16);
|
||||
|
@ -225,6 +228,10 @@ void register_core_types() {
|
|||
|
||||
GDREGISTER_VIRTUAL_CLASS(NativeExtensionManager);
|
||||
|
||||
GDREGISTER_VIRTUAL_CLASS(ResourceUID);
|
||||
|
||||
resource_uid = memnew(ResourceUID);
|
||||
|
||||
native_extension_manager = memnew(NativeExtensionManager);
|
||||
|
||||
ip = IP::create();
|
||||
|
@ -286,6 +293,7 @@ void register_core_singletons() {
|
|||
Engine::get_singleton()->add_singleton(Engine::Singleton("EngineDebugger", _EngineDebugger::get_singleton()));
|
||||
Engine::get_singleton()->add_singleton(Engine::Singleton("Time", Time::get_singleton()));
|
||||
Engine::get_singleton()->add_singleton(Engine::Singleton("NativeExtensionManager", NativeExtensionManager::get_singleton()));
|
||||
Engine::get_singleton()->add_singleton(Engine::Singleton("ResourceUID", ResourceUID::get_singleton()));
|
||||
}
|
||||
|
||||
void register_core_extensions() {
|
||||
|
@ -304,6 +312,8 @@ void unregister_core_types() {
|
|||
native_extension_manager->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_CORE);
|
||||
|
||||
memdelete(native_extension_manager);
|
||||
|
||||
memdelete(resource_uid);
|
||||
memdelete(_resource_loader);
|
||||
memdelete(_resource_saver);
|
||||
memdelete(_os);
|
||||
|
|
|
@ -1259,6 +1259,8 @@
|
|||
<member name="ResourceSaver" type="ResourceSaver" setter="" getter="">
|
||||
The [ResourceSaver] singleton.
|
||||
</member>
|
||||
<member name="ResourceUID" type="ResourceUID" setter="" getter="">
|
||||
</member>
|
||||
<member name="TextServerManager" type="TextServerManager" setter="" getter="">
|
||||
The [TextServerManager] singleton.
|
||||
</member>
|
||||
|
|
73
doc/classes/ResourceUID.xml
Normal file
73
doc/classes/ResourceUID.xml
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="ResourceUID" inherits="Object" version="4.0">
|
||||
<brief_description>
|
||||
</brief_description>
|
||||
<description>
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="add_id">
|
||||
<return type="void">
|
||||
</return>
|
||||
<argument index="0" name="id" type="int">
|
||||
</argument>
|
||||
<argument index="1" name="path" type="String">
|
||||
</argument>
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="create_id" qualifiers="const">
|
||||
<return type="int">
|
||||
</return>
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_id_path" qualifiers="const">
|
||||
<return type="String">
|
||||
</return>
|
||||
<argument index="0" name="id" type="int">
|
||||
</argument>
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="has_id" qualifiers="const">
|
||||
<return type="bool">
|
||||
</return>
|
||||
<argument index="0" name="id" type="int">
|
||||
</argument>
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="id_to_text" qualifiers="const">
|
||||
<return type="String">
|
||||
</return>
|
||||
<argument index="0" name="id" type="int">
|
||||
</argument>
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_id">
|
||||
<return type="void">
|
||||
</return>
|
||||
<argument index="0" name="id" type="int">
|
||||
</argument>
|
||||
<argument index="1" name="path" type="String">
|
||||
</argument>
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="text_to_id" qualifiers="const">
|
||||
<return type="int">
|
||||
</return>
|
||||
<argument index="0" name="text_id" type="String">
|
||||
</argument>
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<constants>
|
||||
<constant name="INVALID_ID" value="-1">
|
||||
</constant>
|
||||
</constants>
|
||||
</class>
|
|
@ -111,7 +111,7 @@ Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) {
|
|||
}
|
||||
}
|
||||
|
||||
if (is_backup_save_enabled() && (p_mode_flags & WRITE) && !(p_mode_flags & READ)) {
|
||||
if (is_backup_save_enabled() && (p_mode_flags == WRITE)) {
|
||||
save_path = path;
|
||||
path = path + ".tmp";
|
||||
}
|
||||
|
|
|
@ -108,7 +108,7 @@ Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) {
|
|||
}
|
||||
#endif
|
||||
|
||||
if (is_backup_save_enabled() && p_mode_flags & WRITE && !(p_mode_flags & READ)) {
|
||||
if (is_backup_save_enabled() && p_mode_flags == WRITE) {
|
||||
save_path = path;
|
||||
path = path + ".tmp";
|
||||
}
|
||||
|
|
|
@ -178,6 +178,15 @@ void DependencyEditor::_update_list() {
|
|||
path = n;
|
||||
type = "Resource";
|
||||
}
|
||||
|
||||
ResourceUID::ID uid = ResourceUID::get_singleton()->text_to_id(path);
|
||||
if (uid != ResourceUID::INVALID_ID) {
|
||||
// dependency is in uid format, obtain proper path
|
||||
ERR_CONTINUE(!ResourceUID::get_singleton()->has_id(uid));
|
||||
|
||||
path = ResourceUID::get_singleton()->get_id_path(uid);
|
||||
}
|
||||
|
||||
String name = path.get_file();
|
||||
|
||||
Ref<Texture2D> icon = EditorNode::get_singleton()->get_class_icon(type);
|
||||
|
|
|
@ -1048,6 +1048,13 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
|
|||
return err;
|
||||
}
|
||||
}
|
||||
if (FileAccess::exists(ResourceUID::CACHE_FILE)) {
|
||||
Vector<uint8_t> array = FileAccess::get_file_as_array(ResourceUID::CACHE_FILE);
|
||||
err = p_func(p_udata, ResourceUID::CACHE_FILE, array, idx, total, enc_in_filters, enc_ex_filters, key);
|
||||
if (err != OK) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// Store text server data if it is supported.
|
||||
if (TS->has_feature(TextServer::FEATURE_USE_SUPPORT_DATA)) {
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
|
||||
EditorFileSystem *EditorFileSystem::singleton = nullptr;
|
||||
//the name is the version, to keep compatibility with different versions of Godot
|
||||
#define CACHE_FILE_NAME "filesystem_cache6"
|
||||
#define CACHE_FILE_NAME "filesystem_cache7"
|
||||
|
||||
void EditorFileSystemDirectory::sort_files() {
|
||||
files.sort_custom<FileInfoSort>();
|
||||
|
@ -116,7 +116,26 @@ String EditorFileSystemDirectory::get_file_path(int p_idx) const {
|
|||
|
||||
Vector<String> EditorFileSystemDirectory::get_file_deps(int p_idx) const {
|
||||
ERR_FAIL_INDEX_V(p_idx, files.size(), Vector<String>());
|
||||
return files[p_idx]->deps;
|
||||
Vector<String> deps;
|
||||
|
||||
for (int i = 0; i < files[p_idx]->deps.size(); i++) {
|
||||
String dep = files[p_idx]->deps[i];
|
||||
int sep_idx = dep.find("::"); //may contain type information, unwanted
|
||||
if (sep_idx != -1) {
|
||||
dep = dep.substr(0, sep_idx);
|
||||
}
|
||||
ResourceUID::ID uid = ResourceUID::get_singleton()->text_to_id(dep);
|
||||
if (uid != ResourceUID::INVALID_ID) {
|
||||
//return proper dependency resoure from uid
|
||||
if (ResourceUID::get_singleton()->has_id(uid)) {
|
||||
dep = ResourceUID::get_singleton()->get_id_path(uid);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
deps.push_back(dep);
|
||||
}
|
||||
return deps;
|
||||
}
|
||||
|
||||
bool EditorFileSystemDirectory::get_file_import_is_valid(int p_idx) const {
|
||||
|
@ -234,7 +253,7 @@ void EditorFileSystem::_scan_filesystem() {
|
|||
|
||||
} else {
|
||||
Vector<String> split = l.split("::");
|
||||
ERR_CONTINUE(split.size() != 8);
|
||||
ERR_CONTINUE(split.size() != 9);
|
||||
String name = split[0];
|
||||
String file;
|
||||
|
||||
|
@ -243,15 +262,16 @@ void EditorFileSystem::_scan_filesystem() {
|
|||
|
||||
FileCache fc;
|
||||
fc.type = split[1];
|
||||
fc.modification_time = split[2].to_int();
|
||||
fc.import_modification_time = split[3].to_int();
|
||||
fc.import_valid = split[4].to_int() != 0;
|
||||
fc.import_group_file = split[5].strip_edges();
|
||||
fc.script_class_name = split[6].get_slice("<>", 0);
|
||||
fc.script_class_extends = split[6].get_slice("<>", 1);
|
||||
fc.script_class_icon_path = split[6].get_slice("<>", 2);
|
||||
fc.uid = split[2].to_int();
|
||||
fc.modification_time = split[3].to_int();
|
||||
fc.import_modification_time = split[4].to_int();
|
||||
fc.import_valid = split[5].to_int() != 0;
|
||||
fc.import_group_file = split[6].strip_edges();
|
||||
fc.script_class_name = split[7].get_slice("<>", 0);
|
||||
fc.script_class_extends = split[7].get_slice("<>", 1);
|
||||
fc.script_class_icon_path = split[7].get_slice("<>", 2);
|
||||
|
||||
String deps = split[7].strip_edges();
|
||||
String deps = split[8].strip_edges();
|
||||
if (deps.length()) {
|
||||
Vector<String> dp = deps.split("<>");
|
||||
for (int i = 0; i < dp.size(); i++) {
|
||||
|
@ -368,6 +388,7 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo
|
|||
Vector<String> dest_files;
|
||||
String dest_md5 = "";
|
||||
int version = 0;
|
||||
bool found_uid = false;
|
||||
|
||||
while (true) {
|
||||
assign = Variant();
|
||||
|
@ -395,6 +416,8 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo
|
|||
version = value;
|
||||
} else if (assign == "importer") {
|
||||
importer_name = value;
|
||||
} else if (assign == "uid") {
|
||||
found_uid = true;
|
||||
} else if (!p_only_imported_files) {
|
||||
if (assign == "source_file") {
|
||||
source_file = value;
|
||||
|
@ -414,6 +437,10 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo
|
|||
return false; //keep mode, do not reimport
|
||||
}
|
||||
|
||||
if (!found_uid) {
|
||||
return true; //UUID not found, old format, reimport.
|
||||
}
|
||||
|
||||
Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(importer_name);
|
||||
|
||||
if (importer->get_format_version() > version) {
|
||||
|
@ -580,6 +607,9 @@ bool EditorFileSystem::_update_scan_actions() {
|
|||
|
||||
if (reimports.size()) {
|
||||
reimport_files(reimports);
|
||||
} else {
|
||||
//reimport files will update the uid cache file so if nothing was reimported, update it manually
|
||||
ResourceUID::get_singleton()->update_cache();
|
||||
}
|
||||
|
||||
if (first_scan) {
|
||||
|
@ -754,6 +784,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess
|
|||
|
||||
if (fc && fc->modification_time == mt && fc->import_modification_time == import_mt && !_test_for_reimport(path, true)) {
|
||||
fi->type = fc->type;
|
||||
fi->uid = fc->uid;
|
||||
fi->deps = fc->deps;
|
||||
fi->modified_time = fc->modification_time;
|
||||
fi->import_modified_time = fc->import_modification_time;
|
||||
|
@ -779,8 +810,14 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess
|
|||
//note: I think this should not happen any longer..
|
||||
}
|
||||
|
||||
if (fc->uid == ResourceUID::INVALID_ID) {
|
||||
// imported files should always have a UUID, so attempt to fetch it.
|
||||
fi->uid = ResourceLoader::get_resource_uid(path);
|
||||
}
|
||||
|
||||
} else {
|
||||
fi->type = ResourceFormatImporter::get_singleton()->get_resource_type(path);
|
||||
fi->uid = ResourceFormatImporter::get_singleton()->get_resource_uid(path);
|
||||
fi->import_group_file = ResourceFormatImporter::get_singleton()->get_import_group_file(path);
|
||||
fi->script_class_name = _get_global_script_class(fi->type, path, &fi->script_class_extends, &fi->script_class_icon_path);
|
||||
fi->modified_time = 0;
|
||||
|
@ -797,6 +834,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess
|
|||
if (fc && fc->modification_time == mt) {
|
||||
//not imported, so just update type if changed
|
||||
fi->type = fc->type;
|
||||
fi->uid = fc->uid;
|
||||
fi->modified_time = fc->modification_time;
|
||||
fi->deps = fc->deps;
|
||||
fi->import_modified_time = 0;
|
||||
|
@ -807,6 +845,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess
|
|||
} else {
|
||||
//new or modified time
|
||||
fi->type = ResourceLoader::get_resource_type(path);
|
||||
fi->uid = ResourceLoader::get_resource_uid(path);
|
||||
fi->script_class_name = _get_global_script_class(fi->type, path, &fi->script_class_extends, &fi->script_class_icon_path);
|
||||
fi->deps = _get_dependencies(path);
|
||||
fi->modified_time = mt;
|
||||
|
@ -815,6 +854,14 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess
|
|||
}
|
||||
}
|
||||
|
||||
if (fi->uid != ResourceUID::INVALID_ID) {
|
||||
if (ResourceUID::get_singleton()->has_id(fi->uid)) {
|
||||
ResourceUID::get_singleton()->set_id(fi->uid, path);
|
||||
} else {
|
||||
ResourceUID::get_singleton()->add_id(fi->uid, path);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
|
||||
ScriptLanguage *lang = ScriptServer::get_language(i);
|
||||
if (lang->supports_documentation() && fi->type == lang->get_type()) {
|
||||
|
@ -1179,7 +1226,7 @@ void EditorFileSystem::_save_filesystem_cache(EditorFileSystemDirectory *p_dir,
|
|||
if (p_dir->files[i]->import_group_file != String()) {
|
||||
group_file_cache.insert(p_dir->files[i]->import_group_file);
|
||||
}
|
||||
String s = p_dir->files[i]->file + "::" + p_dir->files[i]->type + "::" + itos(p_dir->files[i]->modified_time) + "::" + itos(p_dir->files[i]->import_modified_time) + "::" + itos(p_dir->files[i]->import_valid) + "::" + p_dir->files[i]->import_group_file + "::" + p_dir->files[i]->script_class_name + "<>" + p_dir->files[i]->script_class_extends + "<>" + p_dir->files[i]->script_class_icon_path;
|
||||
String s = p_dir->files[i]->file + "::" + p_dir->files[i]->type + "::" + itos(p_dir->files[i]->uid) + "::" + itos(p_dir->files[i]->modified_time) + "::" + itos(p_dir->files[i]->import_modified_time) + "::" + itos(p_dir->files[i]->import_valid) + "::" + p_dir->files[i]->import_group_file + "::" + p_dir->files[i]->script_class_name + "<>" + p_dir->files[i]->script_class_extends + "<>" + p_dir->files[i]->script_class_icon_path;
|
||||
s += "::";
|
||||
for (int j = 0; j < p_dir->files[i]->deps.size(); j++) {
|
||||
if (j > 0) {
|
||||
|
@ -1460,6 +1507,11 @@ void EditorFileSystem::update_file(const String &p_file) {
|
|||
//was removed
|
||||
_delete_internal_files(p_file);
|
||||
if (cpos != -1) { // Might've never been part of the editor file system (*.* files deleted in Open dialog).
|
||||
if (fs->files[cpos]->uid != ResourceUID::INVALID_ID) {
|
||||
if (ResourceUID::get_singleton()->has_id(fs->files[cpos]->uid)) {
|
||||
ResourceUID::get_singleton()->remove_id(fs->files[cpos]->uid);
|
||||
}
|
||||
}
|
||||
memdelete(fs->files[cpos]);
|
||||
fs->files.remove(cpos);
|
||||
}
|
||||
|
@ -1470,6 +1522,7 @@ void EditorFileSystem::update_file(const String &p_file) {
|
|||
}
|
||||
|
||||
String type = ResourceLoader::get_resource_type(p_file);
|
||||
ResourceUID::ID uid = ResourceLoader::get_resource_uid(p_file);
|
||||
|
||||
if (cpos == -1) {
|
||||
// The file did not exist, it was added.
|
||||
|
@ -1502,12 +1555,22 @@ void EditorFileSystem::update_file(const String &p_file) {
|
|||
}
|
||||
|
||||
fs->files[cpos]->type = type;
|
||||
fs->files[cpos]->uid = uid;
|
||||
fs->files[cpos]->script_class_name = _get_global_script_class(type, p_file, &fs->files[cpos]->script_class_extends, &fs->files[cpos]->script_class_icon_path);
|
||||
fs->files[cpos]->import_group_file = ResourceLoader::get_import_group_file(p_file);
|
||||
fs->files[cpos]->modified_time = FileAccess::get_modified_time(p_file);
|
||||
fs->files[cpos]->deps = _get_dependencies(p_file);
|
||||
fs->files[cpos]->import_valid = ResourceLoader::is_import_valid(p_file);
|
||||
|
||||
if (uid != ResourceUID::INVALID_ID) {
|
||||
if (ResourceUID::get_singleton()->has_id(uid)) {
|
||||
ResourceUID::get_singleton()->set_id(uid, p_file);
|
||||
} else {
|
||||
ResourceUID::get_singleton()->add_id(uid, p_file);
|
||||
}
|
||||
|
||||
ResourceUID::get_singleton()->update_cache();
|
||||
}
|
||||
// Update preview
|
||||
EditorResourcePreview::get_singleton()->check_for_invalidation(p_file);
|
||||
|
||||
|
@ -1530,7 +1593,6 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector
|
|||
ERR_CONTINUE(file_importer_name == String());
|
||||
|
||||
if (importer_name != String() && importer_name != file_importer_name) {
|
||||
print_line("one importer '" + importer_name + "' the other '" + file_importer_name + "'.");
|
||||
EditorNode::get_singleton()->show_warning(vformat(TTR("There are multiple importers for different types pointing to file %s, import aborted"), p_group_file));
|
||||
ERR_FAIL_V(ERR_FILE_CORRUPT);
|
||||
}
|
||||
|
@ -1699,6 +1761,8 @@ void EditorFileSystem::_reimport_file(const String &p_file, const Map<StringName
|
|||
params = *p_custom_options;
|
||||
}
|
||||
|
||||
ResourceUID::ID uid = ResourceUID::INVALID_ID;
|
||||
|
||||
if (FileAccess::exists(p_file + ".import")) {
|
||||
//use existing
|
||||
if (p_custom_options == nullptr) {
|
||||
|
@ -1713,8 +1777,16 @@ void EditorFileSystem::_reimport_file(const String &p_file, const Map<StringName
|
|||
params[E] = cf->get_value("params", E);
|
||||
}
|
||||
}
|
||||
if (p_custom_importer == String() && cf->has_section("remap")) {
|
||||
importer_name = cf->get_value("remap", "importer");
|
||||
|
||||
if (cf->has_section("remap")) {
|
||||
if (p_custom_importer == String()) {
|
||||
importer_name = cf->get_value("remap", "importer");
|
||||
}
|
||||
|
||||
if (cf->has_section_key("remap", "uid")) {
|
||||
String uidt = cf->get_value("remap", "uid");
|
||||
uid = ResourceUID::get_singleton()->text_to_id(uidt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1797,6 +1869,12 @@ void EditorFileSystem::_reimport_file(const String &p_file, const Map<StringName
|
|||
f->store_line("type=\"" + importer->get_resource_type() + "\"");
|
||||
}
|
||||
|
||||
if (uid == ResourceUID::INVALID_ID) {
|
||||
uid = ResourceUID::get_singleton()->create_id();
|
||||
}
|
||||
|
||||
f->store_line("uid=\"" + ResourceUID::get_singleton()->id_to_text(uid) + "\""); //store in readable format
|
||||
|
||||
Vector<String> dest_paths;
|
||||
|
||||
if (err == OK) {
|
||||
|
@ -1882,8 +1960,15 @@ void EditorFileSystem::_reimport_file(const String &p_file, const Map<StringName
|
|||
fs->files[cpos]->import_modified_time = FileAccess::get_modified_time(p_file + ".import");
|
||||
fs->files[cpos]->deps = _get_dependencies(p_file);
|
||||
fs->files[cpos]->type = importer->get_resource_type();
|
||||
fs->files[cpos]->uid = uid;
|
||||
fs->files[cpos]->import_valid = ResourceLoader::is_import_valid(p_file);
|
||||
|
||||
if (ResourceUID::get_singleton()->has_id(uid)) {
|
||||
ResourceUID::get_singleton()->set_id(uid, p_file);
|
||||
} else {
|
||||
ResourceUID::get_singleton()->add_id(uid, p_file);
|
||||
}
|
||||
|
||||
//if file is currently up, maybe the source it was loaded from changed, so import math must be updated for it
|
||||
//to reload properly
|
||||
if (ResourceCache::has(p_file)) {
|
||||
|
@ -1934,11 +2019,18 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
|
|||
Set<String> groups_to_reimport;
|
||||
|
||||
for (int i = 0; i < p_files.size(); i++) {
|
||||
String group_file = ResourceFormatImporter::get_singleton()->get_import_group_file(p_files[i]);
|
||||
String file = p_files[i];
|
||||
|
||||
if (group_file_cache.has(p_files[i])) {
|
||||
ResourceUID::ID uid = ResourceUID::get_singleton()->text_to_id(file);
|
||||
if (uid != ResourceUID::INVALID_ID && ResourceUID::get_singleton()->has_id(uid)) {
|
||||
file = ResourceUID::get_singleton()->get_id_path(uid);
|
||||
}
|
||||
|
||||
String group_file = ResourceFormatImporter::get_singleton()->get_import_group_file(file);
|
||||
|
||||
if (group_file_cache.has(file)) {
|
||||
//maybe the file itself is a group!
|
||||
groups_to_reimport.insert(p_files[i]);
|
||||
groups_to_reimport.insert(file);
|
||||
//groups do not belong to grups
|
||||
group_file = String();
|
||||
} else if (group_file != String()) {
|
||||
|
@ -1947,15 +2039,15 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
|
|||
} else {
|
||||
//it's a regular file
|
||||
ImportFile ifile;
|
||||
ifile.path = p_files[i];
|
||||
ResourceFormatImporter::get_singleton()->get_import_order_threads_and_importer(p_files[i], ifile.order, ifile.threaded, ifile.importer);
|
||||
ifile.path = file;
|
||||
ResourceFormatImporter::get_singleton()->get_import_order_threads_and_importer(file, ifile.order, ifile.threaded, ifile.importer);
|
||||
reimport_files.push_back(ifile);
|
||||
}
|
||||
|
||||
//group may have changed, so also update group reference
|
||||
EditorFileSystemDirectory *fs = nullptr;
|
||||
int cpos = -1;
|
||||
if (_find_file(p_files[i], &fs, cpos)) {
|
||||
if (_find_file(file, &fs, cpos)) {
|
||||
fs->files.write[cpos]->import_group_file = group_file;
|
||||
}
|
||||
}
|
||||
|
@ -2020,6 +2112,8 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
|
|||
}
|
||||
}
|
||||
|
||||
ResourceUID::get_singleton()->update_cache(); //after reimporting, update the cache
|
||||
|
||||
_save_filesystem_cache();
|
||||
importing = false;
|
||||
if (!is_scanning()) {
|
||||
|
@ -2104,6 +2198,30 @@ void EditorFileSystem::move_group_file(const String &p_path, const String &p_new
|
|||
}
|
||||
}
|
||||
|
||||
ResourceUID::ID EditorFileSystem::_resource_saver_get_resource_id_for_path(const String &p_path, bool p_generate) {
|
||||
if (!p_path.is_resource_file() || p_path.begins_with("res://.godot")) {
|
||||
//saved externally (configuration file) or internal file, do not assign an ID.
|
||||
return ResourceUID::INVALID_ID;
|
||||
}
|
||||
|
||||
EditorFileSystemDirectory *fs = nullptr;
|
||||
int cpos = -1;
|
||||
|
||||
if (!singleton->_find_file(p_path, &fs, cpos)) {
|
||||
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 UUID 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 UUID at that time, to keep things simple.
|
||||
} else {
|
||||
return ResourceUID::INVALID_ID;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorFileSystem::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_filesystem"), &EditorFileSystem::get_filesystem);
|
||||
ClassDB::bind_method(D_METHOD("is_scanning"), &EditorFileSystem::is_scanning);
|
||||
|
@ -2165,8 +2283,11 @@ EditorFileSystem::EditorFileSystem() {
|
|||
scan_changes_pending = false;
|
||||
revalidate_import_files = false;
|
||||
import_threads.init();
|
||||
ResourceUID::get_singleton()->clear(); //will be updated on scan
|
||||
ResourceSaver::set_get_resource_id_for_path(_resource_saver_get_resource_id_for_path);
|
||||
}
|
||||
|
||||
EditorFileSystem::~EditorFileSystem() {
|
||||
import_threads.finish();
|
||||
ResourceSaver::set_get_resource_id_for_path(nullptr);
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ class EditorFileSystemDirectory : public Object {
|
|||
struct FileInfo {
|
||||
String file;
|
||||
StringName type;
|
||||
ResourceUID::ID uid = ResourceUID::INVALID_ID;
|
||||
uint64_t modified_time = 0;
|
||||
uint64_t import_modified_time = 0;
|
||||
bool import_valid = false;
|
||||
|
@ -159,6 +160,7 @@ class EditorFileSystem : public Node {
|
|||
/* Used for reading the filesystem cache file */
|
||||
struct FileCache {
|
||||
String type;
|
||||
ResourceUID::ID uid = ResourceUID::INVALID_ID;
|
||||
uint64_t modification_time = 0;
|
||||
uint64_t import_modification_time = 0;
|
||||
Vector<String> deps;
|
||||
|
@ -251,6 +253,8 @@ class EditorFileSystem : public Node {
|
|||
|
||||
void _reimport_thread(uint32_t p_index, ImportThreadData *p_import_data);
|
||||
|
||||
static ResourceUID::ID _resource_saver_get_resource_id_for_path(const String &p_path, bool p_generate);
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
|
|
|
@ -1089,6 +1089,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
// Initialize user data dir.
|
||||
OS::get_singleton()->ensure_user_data_dir();
|
||||
|
||||
ResourceUID::get_singleton()->load_from_cache(); // load UUIDs from cache.
|
||||
|
||||
GLOBAL_DEF("memory/limits/multithreaded_server/rid_pool_prealloc", 60);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("memory/limits/multithreaded_server/rid_pool_prealloc",
|
||||
PropertyInfo(Variant::INT,
|
||||
|
|
|
@ -413,6 +413,17 @@ Error ResourceLoaderText::load() {
|
|||
String type = next_tag.fields["type"];
|
||||
String id = next_tag.fields["id"];
|
||||
|
||||
if (next_tag.fields.has("uid")) {
|
||||
String uidt = next_tag.fields["uid"];
|
||||
ResourceUID::ID uid = ResourceUID::get_singleton()->text_to_id(uidt);
|
||||
if (uid != ResourceUID::INVALID_ID && 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);
|
||||
} else {
|
||||
WARN_PRINT(String(res_path + ":" + itos(lines) + " - ext_resource, invalid UUID: " + uidt + " - using text path instead: " + path).utf8().get_data());
|
||||
}
|
||||
}
|
||||
|
||||
if (path.find("://") == -1 && path.is_rel_path()) {
|
||||
// path is relative to file being loaded, so convert to a resource path
|
||||
path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path));
|
||||
|
@ -746,7 +757,18 @@ void ResourceLoaderText::get_dependencies(FileAccess *p_f, List<String> *p_depen
|
|||
String path = next_tag.fields["path"];
|
||||
String type = next_tag.fields["type"];
|
||||
|
||||
if (path.find("://") == -1 && path.is_rel_path()) {
|
||||
bool using_uid = false;
|
||||
if (next_tag.fields.has("uid")) {
|
||||
//if uid exists, return uid in text format, not the path
|
||||
String uidt = next_tag.fields["uid"];
|
||||
ResourceUID::ID uid = ResourceUID::get_singleton()->text_to_id(uidt);
|
||||
if (uid != ResourceUID::INVALID_ID) {
|
||||
path = ResourceUID::get_singleton()->id_to_text(uid);
|
||||
using_uid = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!using_uid && path.find("://") == -1 && path.is_rel_path()) {
|
||||
// path is relative to file being loaded, so convert to a resource path
|
||||
path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path));
|
||||
}
|
||||
|
@ -819,6 +841,14 @@ Error ResourceLoaderText::rename_dependencies(FileAccess *p_f, const String &p_p
|
|||
String id = next_tag.fields["id"];
|
||||
String type = next_tag.fields["type"];
|
||||
|
||||
if (next_tag.fields.has("uid")) {
|
||||
String uidt = next_tag.fields["uid"];
|
||||
ResourceUID::ID uid = ResourceUID::get_singleton()->text_to_id(uidt);
|
||||
if (uid != ResourceUID::INVALID_ID && 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 = base_path.plus_file(path).simplify_path();
|
||||
|
@ -835,7 +865,14 @@ Error ResourceLoaderText::rename_dependencies(FileAccess *p_f, const String &p_p
|
|||
path = base_path.path_to_file(path);
|
||||
}
|
||||
|
||||
fw->store_line("[ext_resource path=\"" + path + "\" type=\"" + type + "\" id=\"" + id + "\"]");
|
||||
String s = "[ext_resource type=\"" + type + "\"";
|
||||
|
||||
ResourceUID::ID uid = ResourceSaver::get_resource_id_for_path(path);
|
||||
if (uid != ResourceUID::INVALID_ID) {
|
||||
s += " uid=\"" + ResourceUID::get_singleton()->id_to_text(uid) + "\"";
|
||||
}
|
||||
s += " path=\"" + path + "\" id=\"" + id + "\"]";
|
||||
fw->store_line(s); // Bundled.
|
||||
|
||||
tag_end = f->get_position();
|
||||
}
|
||||
|
@ -921,6 +958,12 @@ void ResourceLoaderText::open(FileAccess *p_f, bool p_skip_first_tag) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (tag.fields.has("uid")) {
|
||||
res_uid = ResourceUID::get_singleton()->text_to_id(tag.fields["uid"]);
|
||||
} else {
|
||||
res_uid = ResourceUID::INVALID_ID;
|
||||
}
|
||||
|
||||
if (tag.fields.has("load_steps")) {
|
||||
resources_total = tag.fields["load_steps"];
|
||||
} else {
|
||||
|
@ -976,7 +1019,12 @@ Error ResourceLoaderText::save_as_binary(FileAccess *p_f, const String &p_path)
|
|||
|
||||
bs_save_unicode_string(wf.f, is_scene ? "PackedScene" : resource_type);
|
||||
wf->store_64(0); //offset to import metadata, this is no longer used
|
||||
for (int i = 0; i < 14; i++) {
|
||||
|
||||
f->store_32(ResourceFormatSaverBinaryInstance::FORMAT_FLAG_NAMED_SCENE_IDS | ResourceFormatSaverBinaryInstance::FORMAT_FLAG_UIDS);
|
||||
|
||||
f->store_64(res_uid);
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
wf->store_32(0); // reserved
|
||||
}
|
||||
|
||||
|
@ -1018,9 +1066,15 @@ Error ResourceLoaderText::save_as_binary(FileAccess *p_f, const String &p_path)
|
|||
String path = next_tag.fields["path"];
|
||||
String type = next_tag.fields["type"];
|
||||
String id = next_tag.fields["id"];
|
||||
ResourceUID::ID uid = ResourceUID::INVALID_ID;
|
||||
if (next_tag.fields.has("uid")) {
|
||||
String uidt = next_tag.fields["uid"];
|
||||
uid = ResourceUID::get_singleton()->text_to_id(uidt);
|
||||
}
|
||||
|
||||
bs_save_unicode_string(wf.f, type);
|
||||
bs_save_unicode_string(wf.f, path);
|
||||
wf.f->store_64(uid);
|
||||
|
||||
int lindex = dummy_read.external_resources.size();
|
||||
Ref<DummyResource> dr;
|
||||
|
@ -1257,6 +1311,32 @@ String ResourceLoaderText::recognize(FileAccess *p_f) {
|
|||
return tag.fields["type"];
|
||||
}
|
||||
|
||||
ResourceUID::ID ResourceLoaderText::get_uid(FileAccess *p_f) {
|
||||
error = OK;
|
||||
|
||||
lines = 1;
|
||||
f = p_f;
|
||||
|
||||
stream.f = f;
|
||||
|
||||
ignore_resource_parsing = true;
|
||||
|
||||
VariantParser::Tag tag;
|
||||
Error err = VariantParser::parse_tag(&stream, lines, error_text, tag);
|
||||
|
||||
if (err) {
|
||||
_printerr();
|
||||
return ResourceUID::INVALID_ID;
|
||||
}
|
||||
|
||||
if (tag.fields.has("uid")) { //field is optional
|
||||
String uidt = tag.fields["uid"];
|
||||
return ResourceUID::get_singleton()->text_to_id(uidt);
|
||||
}
|
||||
|
||||
return ResourceUID::INVALID_ID;
|
||||
}
|
||||
|
||||
/////////////////////
|
||||
|
||||
RES ResourceFormatLoaderText::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
|
||||
|
@ -1277,7 +1357,6 @@ RES ResourceFormatLoaderText::load(const String &p_path, const String &p_origina
|
|||
loader.local_path = ProjectSettings::get_singleton()->localize_path(path);
|
||||
loader.progress = r_progress;
|
||||
loader.res_path = loader.local_path;
|
||||
//loader.set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) );
|
||||
loader.open(f);
|
||||
err = loader.load();
|
||||
if (r_error) {
|
||||
|
@ -1330,11 +1409,28 @@ String ResourceFormatLoaderText::get_resource_type(const String &p_path) const {
|
|||
ResourceLoaderText loader;
|
||||
loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
|
||||
loader.res_path = loader.local_path;
|
||||
//loader.set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) );
|
||||
String r = loader.recognize(f);
|
||||
return ClassDB::get_compatibility_remapped_class(r);
|
||||
}
|
||||
|
||||
ResourceUID::ID ResourceFormatLoaderText::get_resource_uid(const String &p_path) const {
|
||||
String ext = p_path.get_extension().to_lower();
|
||||
|
||||
if (ext != "tscn" && ext != "tres") {
|
||||
return ResourceUID::INVALID_ID;
|
||||
}
|
||||
|
||||
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
|
||||
if (!f) {
|
||||
return ResourceUID::INVALID_ID; //could not read
|
||||
}
|
||||
|
||||
ResourceLoaderText loader;
|
||||
loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
|
||||
loader.res_path = loader.local_path;
|
||||
return loader.get_uid(f);
|
||||
}
|
||||
|
||||
void ResourceFormatLoaderText::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) {
|
||||
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
|
||||
if (!f) {
|
||||
|
@ -1344,7 +1440,6 @@ void ResourceFormatLoaderText::get_dependencies(const String &p_path, List<Strin
|
|||
ResourceLoaderText loader;
|
||||
loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
|
||||
loader.res_path = loader.local_path;
|
||||
//loader.set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) );
|
||||
loader.get_dependencies(f, p_dependencies, p_add_types);
|
||||
}
|
||||
|
||||
|
@ -1357,7 +1452,6 @@ Error ResourceFormatLoaderText::rename_dependencies(const String &p_path, const
|
|||
ResourceLoaderText loader;
|
||||
loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
|
||||
loader.res_path = loader.local_path;
|
||||
//loader.set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) );
|
||||
return loader.rename_dependencies(f, p_path, p_map);
|
||||
}
|
||||
|
||||
|
@ -1373,7 +1467,6 @@ Error ResourceFormatLoaderText::convert_file_to_binary(const String &p_src_path,
|
|||
const String &path = p_src_path;
|
||||
loader.local_path = ProjectSettings::get_singleton()->localize_path(path);
|
||||
loader.res_path = loader.local_path;
|
||||
//loader.set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) );
|
||||
loader.open(f);
|
||||
return loader.save_as_binary(f, p_dst_path);
|
||||
}
|
||||
|
@ -1548,6 +1641,12 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
|
|||
}
|
||||
title += "format=" + itos(FORMAT_VERSION) + "";
|
||||
|
||||
ResourceUID::ID uid = ResourceSaver::get_resource_id_for_path(local_path, true);
|
||||
|
||||
if (uid != ResourceUID::INVALID_ID) {
|
||||
title += " uid=\"" + ResourceUID::get_singleton()->id_to_text(uid) + "\"";
|
||||
}
|
||||
|
||||
f->store_string(title);
|
||||
f->store_line("]\n"); // One empty line.
|
||||
}
|
||||
|
@ -1612,7 +1711,14 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
|
|||
for (int i = 0; i < sorted_er.size(); i++) {
|
||||
String p = sorted_er[i].resource->get_path();
|
||||
|
||||
f->store_string("[ext_resource path=\"" + p + "\" type=\"" + sorted_er[i].resource->get_save_class() + "\" id=\"" + sorted_er[i].id + "\"]\n"); // Bundled.
|
||||
String s = "[ext_resource type=\"" + sorted_er[i].resource->get_save_class() + "\"";
|
||||
|
||||
ResourceUID::ID uid = ResourceSaver::get_resource_id_for_path(p, false);
|
||||
if (uid != ResourceUID::INVALID_ID) {
|
||||
s += " uid=\"" + ResourceUID::get_singleton()->id_to_text(uid) + "\"";
|
||||
}
|
||||
s += " path=\"" + p + "\" id=\"" + sorted_er[i].id + "\"]\n";
|
||||
f->store_string(s); // Bundled.
|
||||
}
|
||||
|
||||
if (external_resources.size()) {
|
||||
|
|
|
@ -74,6 +74,8 @@ class ResourceLoaderText {
|
|||
|
||||
mutable int lines = 0;
|
||||
|
||||
ResourceUID::ID res_uid = ResourceUID::INVALID_ID;
|
||||
|
||||
Map<String, String> remaps;
|
||||
|
||||
static Error _parse_sub_resources(void *p_self, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) { return reinterpret_cast<ResourceLoaderText *>(p_self)->_parse_sub_resource(p_stream, r_res, line, r_err_str); }
|
||||
|
@ -120,6 +122,7 @@ public:
|
|||
|
||||
void open(FileAccess *p_f, bool p_skip_first_tag = false);
|
||||
String recognize(FileAccess *p_f);
|
||||
ResourceUID::ID get_uid(FileAccess *p_f);
|
||||
void get_dependencies(FileAccess *p_f, List<String> *p_dependencies, bool p_add_types);
|
||||
Error rename_dependencies(FileAccess *p_f, const String &p_path, const Map<String, String> &p_map);
|
||||
|
||||
|
@ -136,6 +139,7 @@ public:
|
|||
virtual void get_recognized_extensions(List<String> *p_extensions) const;
|
||||
virtual bool handles_type(const String &p_type) const;
|
||||
virtual String get_resource_type(const String &p_path) const;
|
||||
virtual ResourceUID::ID get_resource_uid(const String &p_path) const;
|
||||
virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false);
|
||||
virtual Error rename_dependencies(const String &p_path, const Map<String, String> &p_map);
|
||||
|
||||
|
|
Loading…
Reference in a new issue