Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions doc/classes/ProjectSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1180,6 +1180,18 @@
<member name="filesystem/import/fbx2gltf/enabled.web" type="bool" setter="" getter="" default="false">
Override for [member filesystem/import/fbx2gltf/enabled] on the Web where FBX2glTF can't easily be accessed from Godot.
</member>
<member name="filesystem/inline_text_resource_uids/compatibility/no_inline_text_resource_uids_in_addons" type="bool" setter="" getter="" default="false">
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.
</member>
<member name="filesystem/inline_text_resource_uids/gdscript" type="bool" setter="" getter="" default="true">
If [code]true[/code], inline text resource UIDs will be used for [code].gd[/code] files.
</member>
<member name="filesystem/inline_text_resource_uids/shader" type="bool" setter="" getter="" default="true">
if [code]true[/code], inline text resource UIDs will be used for [code].shader[/code] files.
</member>
<member name="filesystem/inline_text_resource_uids/shader_include" type="bool" setter="" getter="" default="true">
if [code]true[/code], inline text resource UIDs will be used for [code].shaderinc[/code] files.
</member>
<member name="gui/common/always_show_focus_state" type="bool" setter="" getter="" default="false">
If [code]true[/code], [Control]s will always show if they're focused, even if said focus was gained via mouse/touch input.
</member>
Expand Down
22 changes: 22 additions & 0 deletions editor/file_system/editor_file_system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
}

Expand Down Expand Up @@ -2468,6 +2480,10 @@ void EditorFileSystem::update_files(const Vector<String> &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 {
Expand All @@ -2484,6 +2500,12 @@ void EditorFileSystem::update_files(const Vector<String> &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);
}
}
}

Expand Down
144 changes: 144 additions & 0 deletions modules/gdscript/gdscript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@

#ifdef TOOLS_ENABLED
#include "editor/gdscript_docgen.h"
#include "editor/script/script_editor_plugin.h"
#endif

#ifdef TESTS_ENABLED
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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<String> 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<FileAccess> 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<FileAccess> 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<String> lines = p_source.split("\n");
bool uid_comment_valid = false;
for (Vector<String>::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<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
Ref<GDScript> sqscr = p_resource;
ERR_FAIL_COND_V(sqscr.is_null(), ERR_INVALID_PARAMETER);
Expand All @@ -3149,6 +3239,20 @@ Error ResourceFormatSaverGDScript::save(const Ref<Resource> &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<FileAccess> 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;
Expand All @@ -3159,6 +3263,14 @@ Error ResourceFormatSaverGDScript::save(const Ref<Resource> &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;
}

Expand All @@ -3171,3 +3283,35 @@ void ResourceFormatSaverGDScript::get_recognized_extensions(const Ref<Resource>
bool ResourceFormatSaverGDScript::recognize(const Ref<Resource> &p_resource) const {
return Object::cast_to<GDScript>(*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<FileAccess> 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<FileAccess> 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;
}
8 changes: 8 additions & 0 deletions modules/gdscript/gdscript.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> *p_dependencies, bool p_add_types = false) override;
virtual void get_classes_used(const String &p_path, HashSet<StringName> *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<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0) override;
virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override;
virtual bool recognize(const Ref<Resource> &p_resource) const override;

virtual Error set_uid(const String &p_path, ResourceUID::ID p_uid) override;
};
6 changes: 6 additions & 0 deletions scene/register_scene_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand All @@ -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);
Expand Down
Loading
Loading