summaryrefslogtreecommitdiff
path: root/editor
diff options
context:
space:
mode:
authorreduz <reduzio@gmail.com>2021-07-23 16:01:18 -0300
committerreduz <reduzio@gmail.com>2021-07-24 09:16:52 -0300
commit32b43cfeb38dc83ba8024acec32bdfc706c86a46 (patch)
tree1ccdbbe010073a37a382955a12f241a83cc384c7 /editor
parentc25fa02c1c242df0f256dd58af650f8c8806c066 (diff)
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.
Diffstat (limited to 'editor')
-rw-r--r--editor/dependency_editor.cpp9
-rw-r--r--editor/editor_export.cpp7
-rw-r--r--editor/editor_file_system.cpp165
-rw-r--r--editor/editor_file_system.h4
4 files changed, 163 insertions, 22 deletions
diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp
index c18b8743cd..9824397076 100644
--- a/editor/dependency_editor.cpp
+++ b/editor/dependency_editor.cpp
@@ -180,6 +180,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);
diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp
index fc483b46b7..3866d866d6 100644
--- a/editor/editor_export.cpp
+++ b/editor/editor_export.cpp
@@ -1050,6 +1050,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)) {
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index 82a71c0e0c..8d7096e9f0 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -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);
-
- String deps = split[7].strip_edges();
+ 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[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) {
@@ -582,6 +609,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) {
@@ -756,6 +786,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;
@@ -781,8 +812,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;
@@ -799,6 +836,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;
@@ -809,6 +847,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;
@@ -817,6 +856,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()) {
@@ -1181,7 +1228,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) {
@@ -1462,6 +1509,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);
}
@@ -1472,6 +1524,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.
@@ -1504,12 +1557,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);
@@ -1532,7 +1595,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);
}
@@ -1702,6 +1764,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) {
@@ -1716,8 +1780,16 @@ void EditorFileSystem::_reimport_file(const String &p_file, const Map<StringName
params[E->get()] = cf->get_value("params", E->get());
}
}
- 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);
+ }
}
}
}
@@ -1800,6 +1872,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) {
@@ -1885,8 +1963,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)) {
@@ -1937,11 +2022,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];
+
+ 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(p_files[i])) {
+ 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()) {
@@ -1950,15 +2042,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;
}
}
@@ -2023,6 +2115,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()) {
@@ -2108,6 +2202,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);
@@ -2169,8 +2287,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);
}
diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h
index 37eee13c16..9dce29d09c 100644
--- a/editor/editor_file_system.h
+++ b/editor/editor_file_system.h
@@ -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();