diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 8941c071b589..e892957fb841 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -1180,6 +1180,18 @@
Override for [member filesystem/import/fbx2gltf/enabled] on the Web where FBX2glTF can't easily be accessed from Godot.
+
+ If [code]true[/code], disables the use of inline text resource UIDs in addons. This is useful for compatibility with old addons that concerning about file's md5.
+
+
+ If [code]true[/code], inline text resource UIDs will be used for [code].gd[/code] files.
+
+
+ if [code]true[/code], inline text resource UIDs will be used for [code].shader[/code] files.
+
+
+ if [code]true[/code], inline text resource UIDs will be used for [code].shaderinc[/code] files.
+
If [code]true[/code], [Control]s will always show if they're focused, even if said focus was gained via mouse/touch input.
diff --git a/editor/file_system/editor_file_system.cpp b/editor/file_system/editor_file_system.cpp
index 6d7ef2690146..972b9e973518 100644
--- a/editor/file_system/editor_file_system.cpp
+++ b/editor/file_system/editor_file_system.cpp
@@ -1364,6 +1364,18 @@ void EditorFileSystem::_process_file_system(const ScannedDirectory *p_scan_dir,
}
f->store_line(ResourceUID::get_singleton()->id_to_text(fi->uid));
}
+ } else {
+ if (fi->uid == ResourceUID::INVALID_ID) {
+ ResourceUID::ID new_uid = ResourceUID::get_singleton()->create_id_for_path(path);
+ if (ResourceSaver::set_uid(path, new_uid) == OK) {
+ fi->uid = new_uid;
+ ResourceUID::get_singleton()->add_id(new_uid, path);
+ }
+ } else {
+ if (ResourceLoader::get_resource_uid(path) != fi->uid) {
+ ResourceSaver::set_uid(path, fi->uid);
+ }
+ }
}
}
@@ -2468,6 +2480,10 @@ void EditorFileSystem::update_files(const Vector &p_script_paths) {
fi->import_valid = (type == "TextFile" || type == "OtherFile") ? true : ResourceLoader::is_import_valid(file);
if (uid != ResourceUID::INVALID_ID) {
+ if (ResourceLoader::get_resource_uid(file) != uid) {
+ ResourceSaver::set_uid(file, uid);
+ }
+
if (ResourceUID::get_singleton()->has_id(uid)) {
ResourceUID::get_singleton()->set_id(uid, file);
} else {
@@ -2484,6 +2500,12 @@ void EditorFileSystem::update_files(const Vector &p_script_paths) {
f->store_line(ResourceUID::get_singleton()->id_to_text(id));
fi->uid = id;
}
+ } else {
+ ResourceUID::ID new_uid = ResourceUID::get_singleton()->create_id_for_path(file);
+ if (ResourceSaver::set_uid(file, new_uid) == OK) {
+ fi->uid = new_uid;
+ ResourceUID::get_singleton()->add_id(new_uid, file);
+ }
}
}
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index b85fd8e74767..d55971a4f361 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -40,6 +40,7 @@
#ifdef TOOLS_ENABLED
#include "editor/gdscript_docgen.h"
+#include "editor/script/script_editor_plugin.h"
#endif
#ifdef TESTS_ENABLED
@@ -2961,6 +2962,8 @@ GDScriptLanguage::GDScriptLanguage() {
track_call_stack = GLOBAL_DEF_RST("debug/settings/gdscript/always_track_call_stacks", false);
track_locals = GLOBAL_DEF_RST("debug/settings/gdscript/always_track_local_variables", false);
+ GLOBAL_DEF("filesystem/inline_text_resource_uids/gdscript", true);
+
#ifdef DEBUG_ENABLED
track_call_stack = true;
track_locals = track_locals || EngineDebugger::is_active();
@@ -3137,6 +3140,93 @@ void ResourceFormatLoaderGDScript::get_classes_used(const String &p_path, HashSe
}
}
+#define UID_COMMENT_PREFIX "# uid://"
+#define UID_COMMENT_SUFFIX "This line is generated, don't modify or remove it."
+static ResourceUID::ID extract_uid_from_line(const String &p_line) {
+ Vector splits = p_line.strip_edges().substr(2).split(" ", false, 1);
+ if (splits.is_empty()) {
+ return ResourceUID::INVALID_ID;
+ }
+ return ResourceUID::get_singleton()->text_to_id(splits[0]);
+}
+
+ResourceUID::ID ResourceFormatLoaderGDScript::get_resource_uid(const String &p_path) const {
+ int64_t uid = ResourceUID::INVALID_ID;
+
+ if (FileAccess::exists(p_path + ".uid")) {
+ Ref file = FileAccess::open(p_path + ".uid", FileAccess::READ);
+ if (file.is_valid()) {
+ uid = ResourceUID::get_singleton()->text_to_id(file->get_line());
+ }
+ } else {
+ const String extension = p_path.get_extension().to_lower();
+ if (extension == "gd") {
+ Ref file = FileAccess::open(p_path, FileAccess::READ);
+ if (file.is_valid()) {
+ while (!file->eof_reached()) {
+ String line = file->get_line().strip_edges();
+ if (!line.is_empty()) {
+ if (line.begins_with(UID_COMMENT_PREFIX)) {
+ uid = extract_uid_from_line(line);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return uid;
+}
+
+bool ResourceFormatLoaderGDScript::has_custom_uid_support() const {
+ return GLOBAL_GET("filesystem/inline_text_resource_uids/gdscript");
+}
+
+String ResourceFormatSaverGDScript::add_uid_to_source(const String &p_source, const String &p_path, ResourceUID::ID p_uid) const {
+ bool need_update = false;
+ Vector lines = p_source.split("\n");
+ bool uid_comment_valid = false;
+ for (Vector::Size i = 0; i < lines.size(); i++) {
+ const String &line = lines[i].strip_edges();
+ if (line.begins_with(UID_COMMENT_PREFIX)) {
+ ResourceUID::ID uid = extract_uid_from_line(line);
+ if (uid == ResourceUID::INVALID_ID || p_uid != uid) {
+ uid = p_uid == ResourceUID::INVALID_ID ? ResourceSaver::get_resource_id_for_path(p_path, true) : p_uid;
+ lines.set(i, vformat("# %s %s", ResourceUID::get_singleton()->id_to_text(uid), UID_COMMENT_SUFFIX));
+ if (ResourceUID::get_singleton()->has_id(uid)) {
+ ResourceUID::get_singleton()->set_id(uid, p_path);
+ } else {
+ ResourceUID::get_singleton()->add_id(uid, p_path);
+ }
+ need_update = true;
+ }
+
+ uid_comment_valid = true;
+ break;
+ } else if (!line.strip_edges().is_empty()) {
+ break;
+ }
+ }
+
+ if (!uid_comment_valid) {
+ ResourceUID::ID uid = p_uid == ResourceUID::INVALID_ID ? ResourceSaver::get_resource_id_for_path(p_path, true) : p_uid;
+ lines.insert(0, vformat("# %s %s", ResourceUID::get_singleton()->id_to_text(uid), UID_COMMENT_SUFFIX));
+ if (ResourceUID::get_singleton()->has_id(uid)) {
+ ResourceUID::get_singleton()->set_id(uid, p_path);
+ } else {
+ ResourceUID::get_singleton()->add_id(uid, p_path);
+ }
+ need_update = true;
+ }
+
+ if (need_update) {
+ return String("\n").join(lines);
+ } else {
+ return p_source;
+ }
+}
+
Error ResourceFormatSaverGDScript::save(const Ref &p_resource, const String &p_path, uint32_t p_flags) {
Ref sqscr = p_resource;
ERR_FAIL_COND_V(sqscr.is_null(), ERR_INVALID_PARAMETER);
@@ -3149,6 +3239,20 @@ Error ResourceFormatSaverGDScript::save(const Ref &p_resource, const S
ERR_FAIL_COND_V_MSG(err, err, "Cannot save GDScript file '" + p_path + "'.");
+ if (!FileAccess::exists(p_path + ".uid")) {
+ if (p_path.begins_with("res://addons/") && GLOBAL_GET("filesystem/inline_text_resource_uids/compatibility/no_inline_text_resource_uids_in_addons")) {
+ Ref f = FileAccess::open(p_path + ".uid", FileAccess::WRITE);
+ if (f.is_valid()) {
+ ResourceUID::ID uid = ResourceUID::get_singleton()->create_id_for_path(p_path);
+ f->store_line(ResourceUID::get_singleton()->id_to_text(uid));
+ f->close();
+ }
+ } else {
+ source = add_uid_to_source(source, p_path);
+ sqscr->set_source_code(source);
+ }
+ }
+
file->store_string(source);
if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
return ERR_CANT_CREATE;
@@ -3159,6 +3263,14 @@ Error ResourceFormatSaverGDScript::save(const Ref &p_resource, const S
GDScriptLanguage::get_singleton()->reload_tool_script(p_resource, true);
}
+#ifdef TOOLS_ENABLED
+ if (ScriptEditor *script_editor = ScriptEditor::get_singleton()) {
+ if (script_editor->get_open_scripts().has(sqscr)) {
+ script_editor->reload_scripts(true);
+ }
+ }
+#endif // TOOLS_ENABLED
+
return OK;
}
@@ -3171,3 +3283,35 @@ void ResourceFormatSaverGDScript::get_recognized_extensions(const Ref
bool ResourceFormatSaverGDScript::recognize(const Ref &p_resource) const {
return Object::cast_to(*p_resource) != nullptr;
}
+
+Error ResourceFormatSaverGDScript::set_uid(const String &p_path, ResourceUID::ID p_uid) {
+ if (FileAccess::exists(p_path + ".uid") || (p_path.begins_with("res://addons/") && GLOBAL_GET("filesystem/inline_text_resource_uids/compatibility/no_inline_text_resource_uids_in_addons"))) {
+ Ref f = FileAccess::open(p_path + ".uid", FileAccess::WRITE);
+ if (f.is_valid()) {
+ f->store_line(ResourceUID::get_singleton()->id_to_text(p_uid));
+ return OK;
+ } else {
+ return FileAccess::get_open_error();
+ }
+ } else if (p_path.get_extension().to_lower() == "gd") {
+ Error err = OK;
+ String source = FileAccess::get_file_as_string(p_path, &err);
+ if (err != OK) {
+ return err;
+ }
+
+ source = add_uid_to_source(source, p_path, p_uid);
+
+ Ref f = FileAccess::open(p_path, FileAccess::WRITE);
+ if (f.is_valid()) {
+ f->store_string(source);
+ err = OK;
+ } else {
+ err = FileAccess::get_open_error();
+ }
+
+ return err;
+ }
+
+ return ERR_FILE_UNRECOGNIZED;
+}
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index f9013d0bf996..4491e734ed56 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -685,13 +685,21 @@ class ResourceFormatLoaderGDScript : public ResourceFormatLoader {
virtual String get_resource_type(const String &p_path) const override;
virtual void get_dependencies(const String &p_path, List *p_dependencies, bool p_add_types = false) override;
virtual void get_classes_used(const String &p_path, HashSet *r_classes) override;
+
+ virtual ResourceUID::ID get_resource_uid(const String &p_path) const override;
+ virtual bool has_custom_uid_support() const override;
};
class ResourceFormatSaverGDScript : public ResourceFormatSaver {
GDSOFTCLASS(ResourceFormatSaverGDScript, ResourceFormatSaver);
+private:
+ String add_uid_to_source(const String &p_source, const String &p_path, ResourceUID::ID p_uid = ResourceUID::INVALID_ID) const;
+
public:
virtual Error save(const Ref &p_resource, const String &p_path, uint32_t p_flags = 0) override;
virtual void get_recognized_extensions(const Ref &p_resource, List *p_extensions) const override;
virtual bool recognize(const Ref &p_resource) const override;
+
+ virtual Error set_uid(const String &p_path, ResourceUID::ID p_uid) override;
};
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 58fadf663a11..90628a459236 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -398,6 +398,8 @@ void register_scene_types() {
resource_loader_shader.instantiate();
ResourceLoader::add_resource_format_loader(resource_loader_shader, true);
+
+ GLOBAL_DEF("filesystem/inline_text_resource_uids/shader", true);
}
if constexpr (GD_IS_CLASS_ENABLED(ShaderInclude)) {
@@ -406,8 +408,12 @@ void register_scene_types() {
resource_loader_shader_include.instantiate();
ResourceLoader::add_resource_format_loader(resource_loader_shader_include, true);
+
+ GLOBAL_DEF("filesystem/inline_text_resource_uids/shader_include", true);
}
+ GLOBAL_DEF("filesystem/inline_text_resource_uids/compatibility/no_inline_text_resource_uids_in_addons", false);
+
OS::get_singleton()->yield(); // may take time to init
GDREGISTER_CLASS(Object);
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index dc07ce7bb5ec..a9116f47419b 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -31,6 +31,7 @@
#include "shader.h"
#include "shader.compat.inc"
+#include "core/config/project_settings.h"
#include "core/io/file_access.h"
#include "scene/main/scene_tree.h"
#include "servers/rendering/rendering_server.h"
@@ -40,6 +41,9 @@
#ifdef TOOLS_ENABLED
#include "editor/doc/editor_help.h"
+#include "editor/editor_node.h"
+#include "editor/shader/shader_editor_plugin.h"
+#include "editor/shader/text_shader_editor.h"
#include "modules/modules_enabled.gen.h" // For regex.
#ifdef MODULE_REGEX_ENABLED
@@ -345,6 +349,93 @@ String ResourceFormatLoaderShader::get_resource_type(const String &p_path) const
return "";
}
+#define UID_COMMENT_PREFIX "// uid://"
+#define UID_COMMENT_SUFFIX "This line is generated, don't modify or remove it."
+static ResourceUID::ID extract_uid_from_line(const String &p_line) {
+ Vector splits = p_line.strip_edges().substr(3).split(" ", false, 1);
+ if (splits.is_empty()) {
+ return ResourceUID::INVALID_ID;
+ }
+ return ResourceUID::get_singleton()->text_to_id(splits[0]);
+}
+
+ResourceUID::ID ResourceFormatLoaderShader::get_resource_uid(const String &p_path) const {
+ int64_t uid = ResourceUID::INVALID_ID;
+
+ if (FileAccess::exists(p_path + ".uid")) {
+ Ref file = FileAccess::open(p_path + ".uid", FileAccess::READ);
+ if (file.is_valid()) {
+ uid = ResourceUID::get_singleton()->text_to_id(file->get_line());
+ }
+ } else {
+ const String extension = p_path.get_extension().to_lower();
+ if (extension == "gdshader") {
+ Ref file = FileAccess::open(p_path, FileAccess::READ);
+ if (file.is_valid()) {
+ while (!file->eof_reached()) {
+ String line = file->get_line().strip_edges();
+ if (!line.is_empty()) {
+ if (line.begins_with(UID_COMMENT_PREFIX)) {
+ uid = extract_uid_from_line(line);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return uid;
+}
+
+bool ResourceFormatLoaderShader::has_custom_uid_support() const {
+ return GLOBAL_GET("filesystem/inline_text_resource_uids/shader");
+}
+
+String ResourceFormatSaverShader::add_uid_to_source(const String &p_source, const String &p_path, ResourceUID::ID p_uid) const {
+ bool need_update = false;
+ Vector lines = p_source.split("\n");
+ bool uid_comment_valid = false;
+ for (Vector::Size i = 0; i < lines.size(); i++) {
+ const String &line = lines[i].strip_edges();
+ if (line.begins_with(UID_COMMENT_PREFIX)) {
+ ResourceUID::ID uid = extract_uid_from_line(line);
+ if (uid == ResourceUID::INVALID_ID || p_uid != uid) {
+ uid = p_uid == ResourceUID::INVALID_ID ? ResourceSaver::get_resource_id_for_path(p_path, true) : p_uid;
+ lines.set(i, vformat("// %s %s", ResourceUID::get_singleton()->id_to_text(uid), UID_COMMENT_SUFFIX));
+ if (ResourceUID::get_singleton()->has_id(uid)) {
+ ResourceUID::get_singleton()->set_id(uid, p_path);
+ } else {
+ ResourceUID::get_singleton()->add_id(uid, p_path);
+ }
+ need_update = true;
+ }
+
+ uid_comment_valid = true;
+ break;
+ } else if (!line.strip_edges().is_empty()) {
+ break;
+ }
+ }
+
+ if (!uid_comment_valid) {
+ ResourceUID::ID uid = p_uid == ResourceUID::INVALID_ID ? ResourceSaver::get_resource_id_for_path(p_path, true) : p_uid;
+ lines.insert(0, vformat("// %s %s", ResourceUID::get_singleton()->id_to_text(uid), UID_COMMENT_SUFFIX));
+ if (ResourceUID::get_singleton()->has_id(uid)) {
+ ResourceUID::get_singleton()->set_id(uid, p_path);
+ } else {
+ ResourceUID::get_singleton()->add_id(uid, p_path);
+ }
+ need_update = true;
+ }
+
+ if (need_update) {
+ return String("\n").join(lines);
+ } else {
+ return p_source;
+ }
+}
+
Error ResourceFormatSaverShader::save(const Ref &p_resource, const String &p_path, uint32_t p_flags) {
Ref shader = p_resource;
ERR_FAIL_COND_V(shader.is_null(), ERR_INVALID_PARAMETER);
@@ -356,6 +447,43 @@ Error ResourceFormatSaverShader::save(const Ref &p_resource, const Str
ERR_FAIL_COND_V_MSG(err, err, "Cannot save shader '" + p_path + "'.");
+ if (!FileAccess::exists(p_path + ".uid")) {
+ if (p_path.begins_with("res://addons/") && GLOBAL_GET("filesystem/inline_text_resource_uids/compatibility/no_inline_text_resource_uids_in_addons")) {
+ Ref f = FileAccess::open(p_path + ".uid", FileAccess::WRITE);
+ if (f.is_valid()) {
+ ResourceUID::ID uid = ResourceUID::get_singleton()->create_id_for_path(p_path);
+ f->store_line(ResourceUID::get_singleton()->id_to_text(uid));
+ f->close();
+ }
+ } else {
+ source = add_uid_to_source(source, p_path);
+ shader->set_code(source);
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ if (ShaderEditorPlugin *shader_editor_plugin = Object::cast_to(EditorNode::get_editor_data().get_editor_by_name("Shader"))) {
+ if (TextShaderEditor *text_shader_editor = Object::cast_to(shader_editor_plugin->get_shader_editor(shader))) {
+ CodeEdit *te = text_shader_editor->get_code_editor()->get_text_editor();
+ int column = te->get_caret_column();
+ int row = te->get_caret_line();
+ int h = te->get_h_scroll();
+ int v = te->get_v_scroll();
+
+ te->set_text(source);
+ te->set_caret_line(row);
+ te->set_caret_column(column);
+ te->set_h_scroll(h);
+ te->set_v_scroll(v);
+
+ te->tag_saved_version();
+
+ text_shader_editor->get_code_editor()->update_line_and_column();
+ }
+ }
+ }
+#endif // TOOLS_ENABLED
+ }
+ }
+
file->store_string(source);
if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
return ERR_CANT_CREATE;
@@ -375,3 +503,35 @@ void ResourceFormatSaverShader::get_recognized_extensions(const Ref &p
bool ResourceFormatSaverShader::recognize(const Ref &p_resource) const {
return p_resource->get_class_name() == "Shader"; //only shader, not inherited
}
+
+Error ResourceFormatSaverShader::set_uid(const String &p_path, ResourceUID::ID p_uid) {
+ if (FileAccess::exists(p_path + ".uid") || (p_path.begins_with("res://addons/") && GLOBAL_GET("filesystem/inline_text_resource_uids/compatibility/no_inline_text_resource_uids_in_addons"))) {
+ Ref f = FileAccess::open(p_path + ".uid", FileAccess::WRITE);
+ if (f.is_valid()) {
+ f->store_line(ResourceUID::get_singleton()->id_to_text(p_uid));
+ return OK;
+ } else {
+ return FileAccess::get_open_error();
+ }
+ } else if (p_path.get_extension().to_lower() == "gdshader") {
+ Error err = OK;
+ String source = FileAccess::get_file_as_string(p_path, &err);
+ if (err != OK) {
+ return err;
+ }
+
+ source = add_uid_to_source(source, p_path, p_uid);
+
+ Ref f = FileAccess::open(p_path, FileAccess::WRITE);
+ if (f.is_valid()) {
+ f->store_string(source);
+ err = OK;
+ } else {
+ err = FileAccess::get_open_error();
+ }
+
+ return err;
+ }
+
+ return ERR_FILE_UNRECOGNIZED;
+}
diff --git a/scene/resources/shader.h b/scene/resources/shader.h
index ff8841173cd8..c9dbbf7797f9 100644
--- a/scene/resources/shader.h
+++ b/scene/resources/shader.h
@@ -113,13 +113,21 @@ class ResourceFormatLoaderShader : public ResourceFormatLoader {
virtual void get_recognized_extensions(List *p_extensions) const override;
virtual bool handles_type(const String &p_type) const override;
virtual String get_resource_type(const String &p_path) const override;
+
+ virtual ResourceUID::ID get_resource_uid(const String &p_path) const override;
+ virtual bool has_custom_uid_support() const override;
};
class ResourceFormatSaverShader : public ResourceFormatSaver {
GDSOFTCLASS(ResourceFormatSaverShader, ResourceFormatSaver);
+private:
+ String add_uid_to_source(const String &p_source, const String &p_path, ResourceUID::ID p_uid = ResourceUID::INVALID_ID) const;
+
public:
virtual Error save(const Ref &p_resource, const String &p_path, uint32_t p_flags = 0) override;
virtual void get_recognized_extensions(const Ref &p_resource, List *p_extensions) const override;
virtual bool recognize(const Ref &p_resource) const override;
+
+ virtual Error set_uid(const String &p_path, ResourceUID::ID p_uid) override;
};
diff --git a/scene/resources/shader_include.cpp b/scene/resources/shader_include.cpp
index b03396bd6fe5..75352cf688b8 100644
--- a/scene/resources/shader_include.cpp
+++ b/scene/resources/shader_include.cpp
@@ -30,9 +30,16 @@
#include "shader_include.h"
+#include "core/config/project_settings.h"
#include "core/io/file_access.h"
#include "servers/rendering/shader_preprocessor.h"
+#ifdef TOOLS_ENABLED
+#include "editor/editor_node.h"
+#include "editor/shader/shader_editor_plugin.h"
+#include "editor/shader/text_shader_editor.h"
+#endif // TOOLS_ENABLED
+
void ShaderInclude::_dependency_changed() {
emit_changed();
}
@@ -128,7 +135,93 @@ String ResourceFormatLoaderShaderInclude::get_resource_type(const String &p_path
return "";
}
+#define UID_COMMENT_PREFIX "// uid://"
+#define UID_COMMENT_SUFFIX "This line is generated, don't modify or remove it."
+static ResourceUID::ID extract_uid_from_line(const String &p_line) {
+ Vector splits = p_line.strip_edges().substr(3).split(" ", false, 1);
+ if (splits.is_empty()) {
+ return ResourceUID::INVALID_ID;
+ }
+ return ResourceUID::get_singleton()->text_to_id(splits[0]);
+}
+
+ResourceUID::ID ResourceFormatLoaderShaderInclude::get_resource_uid(const String &p_path) const {
+ int64_t uid = ResourceUID::INVALID_ID;
+
+ if (FileAccess::exists(p_path + ".uid")) {
+ Ref file = FileAccess::open(p_path + ".uid", FileAccess::READ);
+ if (file.is_valid()) {
+ uid = ResourceUID::get_singleton()->text_to_id(file->get_line());
+ }
+ } else {
+ const String extension = p_path.get_extension().to_lower();
+ if (extension == "gdshaderinc") {
+ Ref file = FileAccess::open(p_path, FileAccess::READ);
+ if (file.is_valid()) {
+ while (!file->eof_reached()) {
+ String line = file->get_line().strip_edges();
+ if (!line.is_empty()) {
+ if (line.begins_with(UID_COMMENT_PREFIX)) {
+ uid = extract_uid_from_line(line);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return uid;
+}
+
+bool ResourceFormatLoaderShaderInclude::has_custom_uid_support() const {
+ return GLOBAL_GET("filesystem/inline_text_resource_uids/shader_include");
+}
+
// ResourceFormatSaverShaderInclude
+String ResourceFormatSaverShaderInclude::add_uid_to_source(const String &p_source, const String &p_path, ResourceUID::ID p_uid) const {
+ bool need_update = false;
+ Vector lines = p_source.split("\n");
+ bool uid_comment_valid = false;
+ for (Vector::Size i = 0; i < lines.size(); i++) {
+ const String &line = lines[i].strip_edges();
+ if (line.begins_with(UID_COMMENT_PREFIX)) {
+ ResourceUID::ID uid = extract_uid_from_line(line);
+ if (uid == ResourceUID::INVALID_ID || p_uid != uid) {
+ uid = p_uid == ResourceUID::INVALID_ID ? ResourceSaver::get_resource_id_for_path(p_path, true) : p_uid;
+ lines.set(i, vformat("// %s %s", ResourceUID::get_singleton()->id_to_text(uid), UID_COMMENT_SUFFIX));
+ if (ResourceUID::get_singleton()->has_id(uid)) {
+ ResourceUID::get_singleton()->set_id(uid, p_path);
+ } else {
+ ResourceUID::get_singleton()->add_id(uid, p_path);
+ }
+ need_update = true;
+ }
+
+ uid_comment_valid = true;
+ break;
+ } else if (!line.strip_edges().is_empty()) {
+ break;
+ }
+ }
+
+ if (!uid_comment_valid) {
+ ResourceUID::ID uid = p_uid == ResourceUID::INVALID_ID ? ResourceSaver::get_resource_id_for_path(p_path, true) : p_uid;
+ lines.insert(0, vformat("// %s %s", ResourceUID::get_singleton()->id_to_text(uid), UID_COMMENT_SUFFIX));
+ if (ResourceUID::get_singleton()->has_id(uid)) {
+ ResourceUID::get_singleton()->set_id(uid, p_path);
+ } else {
+ ResourceUID::get_singleton()->add_id(uid, p_path);
+ }
+ need_update = true;
+ }
+
+ if (need_update) {
+ return String("\n").join(lines);
+ } else {
+ return p_source;
+ }
+}
Error ResourceFormatSaverShaderInclude::save(const Ref &p_resource, const String &p_path, uint32_t p_flags) {
Ref shader_inc = p_resource;
@@ -141,6 +234,43 @@ Error ResourceFormatSaverShaderInclude::save(const Ref &p_resource, co
ERR_FAIL_COND_V_MSG(error, error, "Cannot save shader include '" + p_path + "'.");
+ if (!FileAccess::exists(p_path + ".uid")) {
+ if (p_path.begins_with("res://addons/") && GLOBAL_GET("filesystem/inline_text_resource_uids/compatibility/no_inline_text_resource_uids_in_addons")) {
+ Ref f = FileAccess::open(p_path + ".uid", FileAccess::WRITE);
+ if (f.is_valid()) {
+ ResourceUID::ID uid = ResourceUID::get_singleton()->create_id_for_path(p_path);
+ f->store_line(ResourceUID::get_singleton()->id_to_text(uid));
+ f->close();
+ }
+ } else {
+ source = add_uid_to_source(source, p_path);
+ shader_inc->set_code(source);
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ if (ShaderEditorPlugin *shader_editor_plugin = Object::cast_to(EditorNode::get_editor_data().get_editor_by_name("Shader"))) {
+ if (TextShaderEditor *text_shader_editor = Object::cast_to(shader_editor_plugin->get_shader_editor(shader_inc))) {
+ CodeEdit *te = text_shader_editor->get_code_editor()->get_text_editor();
+ int column = te->get_caret_column();
+ int row = te->get_caret_line();
+ int h = te->get_h_scroll();
+ int v = te->get_v_scroll();
+
+ te->set_text(source);
+ te->set_caret_line(row);
+ te->set_caret_column(column);
+ te->set_h_scroll(h);
+ te->set_v_scroll(v);
+
+ te->tag_saved_version();
+
+ text_shader_editor->get_code_editor()->update_line_and_column();
+ }
+ }
+ }
+#endif // TOOLS_ENABLED
+ }
+ }
+
file->store_string(source);
if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
return ERR_CANT_CREATE;
@@ -159,3 +289,35 @@ void ResourceFormatSaverShaderInclude::get_recognized_extensions(const Ref &p_resource) const {
return p_resource->get_class_name() == "ShaderInclude"; //only shader, not inherited
}
+
+Error ResourceFormatSaverShaderInclude::set_uid(const String &p_path, ResourceUID::ID p_uid) {
+ if (FileAccess::exists(p_path + ".uid") || (p_path.begins_with("res://addons/") && GLOBAL_GET("filesystem/inline_text_resource_uids/compatibility/no_inline_text_resource_uids_in_addons"))) {
+ Ref f = FileAccess::open(p_path + ".uid", FileAccess::WRITE);
+ if (f.is_valid()) {
+ f->store_line(ResourceUID::get_singleton()->id_to_text(p_uid));
+ return OK;
+ } else {
+ return FileAccess::get_open_error();
+ }
+ } else if (p_path.get_extension().to_lower() == "gdshaderinc") {
+ Error err = OK;
+ String source = FileAccess::get_file_as_string(p_path, &err);
+ if (err != OK) {
+ return err;
+ }
+
+ source = add_uid_to_source(source, p_path, p_uid);
+
+ Ref f = FileAccess::open(p_path, FileAccess::WRITE);
+ if (f.is_valid()) {
+ f->store_string(source);
+ err = OK;
+ } else {
+ err = FileAccess::get_open_error();
+ }
+
+ return err;
+ }
+
+ return ERR_FILE_UNRECOGNIZED;
+}
diff --git a/scene/resources/shader_include.h b/scene/resources/shader_include.h
index 0930f5b47597..4b4139a29ccf 100644
--- a/scene/resources/shader_include.h
+++ b/scene/resources/shader_include.h
@@ -63,13 +63,21 @@ class ResourceFormatLoaderShaderInclude : public ResourceFormatLoader {
virtual void get_recognized_extensions(List *p_extensions) const override;
virtual bool handles_type(const String &p_type) const override;
virtual String get_resource_type(const String &p_path) const override;
+
+ virtual ResourceUID::ID get_resource_uid(const String &p_path) const override;
+ virtual bool has_custom_uid_support() const override;
};
class ResourceFormatSaverShaderInclude : public ResourceFormatSaver {
GDSOFTCLASS(ResourceFormatSaverShaderInclude, ResourceFormatSaver);
+private:
+ String add_uid_to_source(const String &p_source, const String &p_path, ResourceUID::ID p_uid = ResourceUID::INVALID_ID) const;
+
public:
virtual Error save(const Ref &p_resource, const String &p_path, uint32_t p_flags = 0) override;
virtual void get_recognized_extensions(const Ref &p_resource, List *p_extensions) const override;
virtual bool recognize(const Ref &p_resource) const override;
+
+ virtual Error set_uid(const String &p_path, ResourceUID::ID p_uid) override;
};