Support script global resource name in EditorFileSystem

* Works for binary and text files.
* Makes EditorQuickOpen work with custom resources again.
* Information is cached and easily accessible.

Properly fixes #66179. Supersedes #66215 and supersedes #62417

**WARNING**: This required breaking backwards binary compatibility (.res and .scn files). Files saved after this PR is merged will no longer open in any earlier versions of Godot.
This commit is contained in:
Juan Linietsky 2023-01-19 19:12:25 +01:00
parent 14fdd28de9
commit dddd8d43f6
17 changed files with 250 additions and 18 deletions

View file

@ -91,7 +91,8 @@ enum {
// Version 2: added 64 bits support for float and int.
// Version 3: changed nodepath encoding.
// Version 4: new string ID for ext/subresources, breaks forward compat.
FORMAT_VERSION = 4,
// Version 5: Ability to store script class in the header.
FORMAT_VERSION = 5,
FORMAT_VERSION_CAN_RENAME_DEPS = 1,
FORMAT_VERSION_NO_NODEPATH_PROPERTY = 3,
};
@ -1013,6 +1014,10 @@ void ResourceLoaderBinary::open(Ref<FileAccess> p_f, bool p_no_resources, bool p
uid = ResourceUID::INVALID_ID;
}
if (flags & ResourceFormatSaverBinaryInstance::FORMAT_FLAG_HAS_SCRIPT_CLASS) {
script_class = get_unicode_string();
}
for (int i = 0; i < ResourceFormatSaverBinaryInstance::RESERVED_FIELDS; i++) {
f->get_32(); //skip a few reserved fields
}
@ -1117,6 +1122,57 @@ String ResourceLoaderBinary::recognize(Ref<FileAccess> p_f) {
return get_unicode_string();
}
String ResourceLoaderBinary::recognize_script_class(Ref<FileAccess> p_f) {
error = OK;
f = p_f;
uint8_t header[4];
f->get_buffer(header, 4);
if (header[0] == 'R' && header[1] == 'S' && header[2] == 'C' && header[3] == 'C') {
// Compressed.
Ref<FileAccessCompressed> fac;
fac.instantiate();
error = fac->open_after_magic(f);
if (error != OK) {
f.unref();
return "";
}
f = fac;
} else if (header[0] != 'R' || header[1] != 'S' || header[2] != 'R' || header[3] != 'C') {
// Not normal.
error = ERR_FILE_UNRECOGNIZED;
f.unref();
return "";
}
bool big_endian = f->get_32();
f->get_32(); // use_real64
f->set_big_endian(big_endian != 0); //read big endian if saved as big endian
uint32_t ver_major = f->get_32();
f->get_32(); // ver_minor
uint32_t ver_fmt = f->get_32();
if (ver_fmt > FORMAT_VERSION || ver_major > VERSION_MAJOR) {
f.unref();
return "";
}
get_unicode_string(); // type
f->get_64(); // Metadata offset
uint32_t flags = f->get_32();
f->get_64(); // UID
if (flags & ResourceFormatSaverBinaryInstance::FORMAT_FLAG_HAS_SCRIPT_CLASS) {
return get_unicode_string();
} else {
return String();
}
}
Ref<Resource> ResourceFormatLoaderBinary::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) {
if (r_error) {
*r_error = ERR_FILE_CANT_OPEN;
@ -1299,6 +1355,9 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
fw->store_32(flags);
fw->store_64(uid_data);
if (flags & ResourceFormatSaverBinaryInstance::FORMAT_FLAG_HAS_SCRIPT_CLASS) {
save_ustring(fw, get_ustring(f));
}
for (int i = 0; i < ResourceFormatSaverBinaryInstance::RESERVED_FIELDS; i++) {
fw->store_32(0); // reserved
@ -1420,6 +1479,18 @@ String ResourceFormatLoaderBinary::get_resource_type(const String &p_path) const
return ClassDB::get_compatibility_remapped_class(r);
}
String ResourceFormatLoaderBinary::get_resource_script_class(const String &p_path) const {
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
if (f.is_null()) {
return ""; //could not read
}
ResourceLoaderBinary loader;
loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
loader.res_path = loader.local_path;
return loader.recognize_script_class(f);
}
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)) {
@ -2037,15 +2108,31 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const Ref<Re
save_unicode_string(f, _resource_get_class(p_resource));
f->store_64(0); //offset to import metadata
String script_class;
{
uint32_t format_flags = FORMAT_FLAG_NAMED_SCENE_IDS | FORMAT_FLAG_UIDS;
#ifdef REAL_T_IS_DOUBLE
format_flags |= FORMAT_FLAG_REAL_T_IS_DOUBLE;
#endif
if (!p_resource->is_class("PackedScene")) {
Ref<Script> s = p_resource->get_script();
if (s.is_valid()) {
script_class = s->get_global_name();
if (!script_class.is_empty()) {
format_flags |= ResourceFormatSaverBinaryInstance::FORMAT_FLAG_HAS_SCRIPT_CLASS;
}
}
}
f->store_32(format_flags);
}
ResourceUID::ID uid = ResourceSaver::get_resource_id_for_path(p_path, true);
f->store_64(uid);
if (!script_class.is_empty()) {
save_unicode_string(f, script_class);
}
for (int i = 0; i < ResourceFormatSaverBinaryInstance::RESERVED_FIELDS; i++) {
f->store_32(0); // reserved
}
@ -2298,6 +2385,10 @@ Error ResourceFormatSaverBinaryInstance::set_uid(const String &p_path, ResourceU
fw->store_32(flags);
fw->store_64(p_uid);
if (flags & ResourceFormatSaverBinaryInstance::FORMAT_FLAG_HAS_SCRIPT_CLASS) {
save_ustring(fw, get_ustring(f));
}
//rest of file
uint8_t b = f->get_8();
while (!f->eof_reached()) {

View file

@ -65,6 +65,7 @@ class ResourceLoaderBinary {
bool using_named_scene_ids = false;
bool using_uids = false;
String script_class;
bool use_sub_threads = false;
float *progress = nullptr;
Vector<ExtResource> external_resources;
@ -100,6 +101,7 @@ public:
void set_remaps(const HashMap<String, String> &p_remaps) { remaps = p_remaps; }
void open(Ref<FileAccess> p_f, bool p_no_resources = false, bool p_keep_uuid_paths = false);
String recognize(Ref<FileAccess> p_f);
String recognize_script_class(Ref<FileAccess> p_f);
void get_dependencies(Ref<FileAccess> p_f, List<String> *p_dependencies, bool p_add_types);
void get_classes_used(Ref<FileAccess> p_f, HashSet<StringName> *p_classes);
@ -113,6 +115,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 String get_resource_script_class(const String &p_path) const;
virtual void get_classes_used(const String &p_path, HashSet<StringName> *r_classes);
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);
@ -165,6 +168,7 @@ public:
FORMAT_FLAG_NAMED_SCENE_IDS = 1,
FORMAT_FLAG_UIDS = 2,
FORMAT_FLAG_REAL_T_IS_DOUBLE = 4,
FORMAT_FLAG_HAS_SCRIPT_CLASS = 8,
// Amount of reserved 32-bit fields in resource header
RESERVED_FIELDS = 11

View file

@ -99,6 +99,12 @@ String ResourceFormatLoader::get_resource_type(const String &p_path) const {
return ret;
}
String ResourceFormatLoader::get_resource_script_class(const String &p_path) const {
String ret;
GDVIRTUAL_CALL(_get_resource_script_class, p_path, ret);
return ret;
}
ResourceUID::ID ResourceFormatLoader::get_resource_uid(const String &p_path) const {
int64_t uid = ResourceUID::INVALID_ID;
GDVIRTUAL_CALL(_get_resource_uid, p_path, uid);
@ -184,6 +190,7 @@ void ResourceFormatLoader::_bind_methods() {
GDVIRTUAL_BIND(_recognize_path, "path", "type");
GDVIRTUAL_BIND(_handles_type, "type");
GDVIRTUAL_BIND(_get_resource_type, "path");
GDVIRTUAL_BIND(_get_resource_script_class, "path");
GDVIRTUAL_BIND(_get_resource_uid, "path");
GDVIRTUAL_BIND(_get_dependencies, "path", "add_types");
GDVIRTUAL_BIND(_rename_dependencies, "path", "renames");
@ -764,6 +771,19 @@ String ResourceLoader::get_resource_type(const String &p_path) {
return "";
}
String ResourceLoader::get_resource_script_class(const String &p_path) {
String local_path = _validate_local_path(p_path);
for (int i = 0; i < loader_count; i++) {
String result = loader[i]->get_resource_script_class(local_path);
if (!result.is_empty()) {
return result;
}
}
return "";
}
ResourceUID::ID ResourceLoader::get_resource_uid(const String &p_path) {
String local_path = _validate_local_path(p_path);

View file

@ -54,6 +54,7 @@ protected:
GDVIRTUAL2RC(bool, _recognize_path, String, StringName)
GDVIRTUAL1RC(bool, _handles_type, StringName)
GDVIRTUAL1RC(String, _get_resource_type, String)
GDVIRTUAL1RC(String, _get_resource_script_class, String)
GDVIRTUAL1RC(ResourceUID::ID, _get_resource_uid, String)
GDVIRTUAL2RC(Vector<String>, _get_dependencies, String, bool)
GDVIRTUAL1RC(Vector<String>, _get_classes_used, String)
@ -71,6 +72,7 @@ public:
virtual bool handles_type(const String &p_type) const;
virtual void get_classes_used(const String &p_path, HashSet<StringName> *r_classes);
virtual String get_resource_type(const String &p_path) const;
virtual String get_resource_script_class(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 HashMap<String, String> &p_map);
@ -175,6 +177,7 @@ public:
static void remove_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader);
static void get_classes_used(const String &p_path, HashSet<StringName> *r_classes);
static String get_resource_type(const String &p_path);
static String get_resource_script_class(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 HashMap<String, String> &p_map);

View file

@ -120,7 +120,7 @@ public:
virtual bool can_instantiate() const = 0;
virtual Ref<Script> get_base_script() const = 0; //for script inheritance
virtual StringName get_global_name() const = 0;
virtual bool inherits_script(const Ref<Script> &p_script) const = 0;
virtual StringName get_instance_base_type() const = 0; // this may not work in all scripts, will return empty if so

View file

@ -53,6 +53,7 @@ protected:
public:
EXBIND0RC(bool, can_instantiate)
EXBIND0RC(Ref<Script>, get_base_script)
EXBIND0RC(StringName, get_global_name)
EXBIND1RC(bool, inherits_script, const Ref<Script> &)
EXBIND0RC(StringName, get_instance_base_type)

View file

@ -38,6 +38,13 @@
Gets the list of extensions for files this loader is able to read.
</description>
</method>
<method name="_get_resource_script_class" qualifiers="virtual const">
<return type="String" />
<param index="0" name="path" type="String" />
<description>
Returns the script class name associated with the [Resource] under the given [param path]. If the resource has no script or the script isn't a named class, it should return [code]""[/code].
</description>
</method>
<method name="_get_resource_type" qualifiers="virtual const">
<return type="String" />
<param index="0" name="path" type="String" />

View file

@ -47,7 +47,7 @@
EditorFileSystem *EditorFileSystem::singleton = nullptr;
//the name is the version, to keep compatibility with different versions of Godot
#define CACHE_FILE_NAME "filesystem_cache7"
#define CACHE_FILE_NAME "filesystem_cache8"
void EditorFileSystemDirectory::sort_files() {
files.sort_custom<FileInfoSort>();
@ -169,6 +169,11 @@ StringName EditorFileSystemDirectory::get_file_type(int p_idx) const {
return files[p_idx]->type;
}
StringName EditorFileSystemDirectory::get_file_resource_script_class(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, files.size(), "");
return files[p_idx]->resource_script_class;
}
String EditorFileSystemDirectory::get_name() {
return name;
}
@ -266,6 +271,10 @@ void EditorFileSystem::_scan_filesystem() {
FileCache fc;
fc.type = split[1];
if (fc.type.find("/") != -1) {
fc.type = fc.type.get_slice("/", 0);
fc.resource_script_class = fc.type.get_slice("/", 1);
}
fc.uid = split[2].to_int();
fc.modification_time = split[3].to_int();
fc.import_modification_time = split[4].to_int();
@ -854,6 +863,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
if (fc && fc->modification_time == mt && fc->import_modification_time == import_mt && !_test_for_reimport(path, true)) {
fi->type = fc->type;
fi->resource_script_class = fc->resource_script_class;
fi->uid = fc->uid;
fi->deps = fc->deps;
fi->modified_time = fc->modification_time;
@ -875,6 +885,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
if (fc->type.is_empty()) {
fi->type = ResourceLoader::get_resource_type(path);
fi->resource_script_class = ResourceLoader::get_resource_script_class(path);
fi->import_group_file = ResourceLoader::get_import_group_file(path);
//there is also the chance that file type changed due to reimport, must probably check this somehow here (or kind of note it for next time in another file?)
//note: I think this should not happen any longer..
@ -904,6 +915,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
if (fc && fc->modification_time == mt) {
//not imported, so just update type if changed
fi->type = fc->type;
fi->resource_script_class = fc->resource_script_class;
fi->uid = fc->uid;
fi->modified_time = fc->modification_time;
fi->deps = fc->deps;
@ -915,6 +927,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
} else {
//new or modified time
fi->type = ResourceLoader::get_resource_type(path);
fi->resource_script_class = ResourceLoader::get_resource_script_class(path);
if (fi->type == "" && textfile_extensions.has(ext)) {
fi->type = "TextFile";
}
@ -1029,6 +1042,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
fi->modified_time = FileAccess::get_modified_time(path);
fi->import_modified_time = 0;
fi->type = ResourceLoader::get_resource_type(path);
fi->resource_script_class = ResourceLoader::get_resource_script_class(path);
if (fi->type == "" && textfile_extensions.has(ext)) {
fi->type = "TextFile";
}
@ -1285,7 +1299,12 @@ void EditorFileSystem::_save_filesystem_cache(EditorFileSystemDirectory *p_dir,
if (!p_dir->files[i]->import_group_file.is_empty()) {
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]->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;
String type = p_dir->files[i]->type;
if (p_dir->files[i]->resource_script_class) {
type += "/" + String(p_dir->files[i]->resource_script_class);
}
String s = p_dir->files[i]->file + "::" + 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) {
@ -1612,6 +1631,8 @@ void EditorFileSystem::update_file(const String &p_file) {
if (type.is_empty() && textfile_extensions.has(p_file.get_extension())) {
type = "TextFile";
}
String script_class = ResourceLoader::get_resource_script_class(p_file);
ResourceUID::ID uid = ResourceLoader::get_resource_uid(p_file);
if (cpos == -1) {
@ -1645,6 +1666,7 @@ void EditorFileSystem::update_file(const String &p_file) {
}
fs->files[cpos]->type = type;
fs->files[cpos]->resource_script_class = script_class;
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);

View file

@ -54,6 +54,7 @@ class EditorFileSystemDirectory : public Object {
struct FileInfo {
String file;
StringName type;
StringName resource_script_class; // If any resource has script with a global class name, its found here.
ResourceUID::ID uid = ResourceUID::INVALID_ID;
uint64_t modified_time = 0;
uint64_t import_modified_time = 0;
@ -61,6 +62,7 @@ class EditorFileSystemDirectory : public Object {
String import_group_file;
Vector<String> deps;
bool verified = false; //used for checking changes
// These are for script resources only.
String script_class_name;
String script_class_extends;
String script_class_icon_path;
@ -90,6 +92,7 @@ public:
String get_file(int p_idx) const;
String get_file_path(int p_idx) const;
StringName get_file_type(int p_idx) const;
StringName get_file_resource_script_class(int p_idx) const;
Vector<String> get_file_deps(int p_idx) const;
bool get_file_import_is_valid(int p_idx) const;
uint64_t get_file_modified_time(int p_idx) const;
@ -189,6 +192,7 @@ class EditorFileSystem : public Node {
/* Used for reading the filesystem cache file */
struct FileCache {
String type;
String resource_script_class;
ResourceUID::ID uid = ResourceUID::INVALID_ID;
uint64_t modification_time = 0;
uint64_t import_modification_time = 0;

View file

@ -69,17 +69,9 @@ void EditorQuickOpen::_build_search_cache(EditorFileSystemDirectory *p_efsd) {
for (int i = 0; i < p_efsd->get_file_count(); i++) {
String file = p_efsd->get_file_path(i);
String engine_type = p_efsd->get_file_type(i);
// TODO: Fix lack of caching for resource's script's global class name (if applicable).
String script_type;
if (_load_resources) {
Ref<Resource> res = ResourceLoader::load(file);
if (res.is_valid()) {
Ref<Script> scr = res->get_script();
if (scr.is_valid()) {
script_type = scr->get_language()->get_global_class_name(file);
}
}
}
String script_type = p_efsd->get_file_resource_script_class(i);
String actual_type = script_type.is_empty() ? engine_type : script_type;
// Iterate all possible base types.
for (String &parent_type : base_types) {

View file

@ -43,7 +43,6 @@ class EditorQuickOpen : public ConfirmationDialog {
Tree *search_options = nullptr;
String base_type;
bool allow_multi_select = false;
bool _load_resources = false; // Prohibitively slow for now.
Vector<String> files;
OAHashMap<String, Ref<Texture2D>> icons;

View file

@ -248,6 +248,10 @@ Ref<Script> GDScript::get_base_script() const {
}
}
StringName GDScript::get_global_name() const {
return name;
}
StringName GDScript::get_instance_base_type() const {
if (native.is_valid()) {
return native->get_name();

View file

@ -228,6 +228,7 @@ public:
virtual bool can_instantiate() const override;
virtual Ref<Script> get_base_script() const override;
virtual StringName get_global_name() const override;
virtual StringName get_instance_base_type() const override; // this may not work in all scripts, will return empty if so
virtual ScriptInstance *instance_create(Object *p_this) override;

View file

@ -2606,6 +2606,10 @@ Ref<Script> CSharpScript::get_base_script() const {
return base_script;
}
StringName CSharpScript::get_global_name() const {
return StringName();
}
void CSharpScript::get_script_property_list(List<PropertyInfo> *r_list) const {
#ifdef TOOLS_ENABLED
const CSharpScript *top = this;

View file

@ -186,6 +186,8 @@ public:
bool inherits_script(const Ref<Script> &p_script) const override;
Ref<Script> get_base_script() const override;
StringName get_global_name() const override;
ScriptLanguage *get_language() const override;
void get_script_method_list(List<MethodInfo> *p_list) const override;

View file

@ -927,7 +927,11 @@ Error ResourceLoaderText::rename_dependencies(Ref<FileAccess> p_f, const String
if (is_scene) {
fw->store_line("[gd_scene load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + "]\n");
} else {
fw->store_line("[gd_resource type=\"" + res_type + "\" load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + "]\n");
String script_res_text;
if (!script_class.is_empty()) {
script_res_text = "script_class=\"" + script_class + "\" ";
}
fw->store_line("[gd_resource type=\"" + res_type + "\" " + script_res_text + "load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + "]\n");
}
}
@ -1051,6 +1055,10 @@ void ResourceLoaderText::open(Ref<FileAccess> p_f, bool p_skip_first_tag) {
return;
}
if (tag.fields.has("script_class")) {
script_class = tag.fields["script_class"];
}
res_type = tag.fields["type"];
} else {
@ -1497,6 +1505,44 @@ Error ResourceLoaderText::get_classes_used(HashSet<StringName> *r_classes) {
return OK;
}
String ResourceLoaderText::recognize_script_class(Ref<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 "";
}
if (tag.fields.has("format")) {
int fmt = tag.fields["format"];
if (fmt > FORMAT_VERSION) {
error_text = "Saved with newer format version";
_printerr();
return "";
}
}
if (tag.name != "gd_resource") {
return "";
}
if (tag.fields.has("script_class")) {
return tag.fields["script_class"];
}
return "";
}
String ResourceLoaderText::recognize(Ref<FileAccess> p_f) {
error = OK;
@ -1666,6 +1712,25 @@ String ResourceFormatLoaderText::get_resource_type(const String &p_path) const {
return ClassDB::get_compatibility_remapped_class(r);
}
String ResourceFormatLoaderText::get_resource_script_class(const String &p_path) const {
String ext = p_path.get_extension().to_lower();
if (ext != "tres") {
return String();
}
// ...for anything else must test...
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
if (f.is_null()) {
return ""; //could not read
}
ResourceLoaderText loader;
loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path);
loader.res_path = loader.local_path;
return loader.recognize_script_class(f);
}
ResourceUID::ID ResourceFormatLoaderText::get_resource_uid(const String &p_path) const {
String ext = p_path.get_extension().to_lower();
@ -1909,7 +1974,12 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
String title = packed_scene.is_valid() ? "[gd_scene " : "[gd_resource ";
if (packed_scene.is_null()) {
title += "type=\"" + _resource_get_class(p_resource) + "\" ";
Ref<Script> script = p_resource->get_script();
if (script.is_valid() && script->get_global_name()) {
title += "script_class=\"" + String(script->get_global_name()) + "\" ";
}
}
int load_steps = saved_resources.size() + external_resources.size();
if (load_steps > 1) {
@ -2248,7 +2318,12 @@ Error ResourceLoaderText::set_uid(Ref<FileAccess> p_f, ResourceUID::ID p_uid) {
if (is_scene) {
fw->store_string("[gd_scene load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + " uid=\"" + ResourceUID::get_singleton()->id_to_text(p_uid) + "\"]");
} else {
fw->store_string("[gd_resource type=\"" + res_type + "\" load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + " uid=\"" + ResourceUID::get_singleton()->id_to_text(p_uid) + "\"]");
String script_res_text;
if (!script_class.is_empty()) {
script_res_text = "script_class=\"" + script_class + "\" ";
}
fw->store_string("[gd_resource type=\"" + res_type + "\" " + script_res_text + "load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + " uid=\"" + ResourceUID::get_singleton()->id_to_text(p_uid) + "\"]");
}
uint8_t c = f->get_8();

View file

@ -64,6 +64,7 @@ class ResourceLoaderText {
int resources_total = 0;
int resource_current = 0;
String resource_type;
String script_class;
VariantParser::Tag next_tag;
@ -125,6 +126,7 @@ public:
void open(Ref<FileAccess> p_f, bool p_skip_first_tag = false);
String recognize(Ref<FileAccess> p_f);
String recognize_script_class(Ref<FileAccess> p_f);
ResourceUID::ID get_uid(Ref<FileAccess> p_f);
void get_dependencies(Ref<FileAccess> p_f, List<String> *p_dependencies, bool p_add_types);
Error rename_dependencies(Ref<FileAccess> p_f, const String &p_path, const HashMap<String, String> &p_map);
@ -144,6 +146,7 @@ public:
virtual void get_classes_used(const String &p_path, HashSet<StringName> *r_classes);
virtual String get_resource_type(const String &p_path) const;
virtual String get_resource_script_class(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 HashMap<String, String> &p_map);