Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support script global resource name in EditorFileSystem #71687

Merged
Merged
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
93 changes: 92 additions & 1 deletion core/io/resource_format_binary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -1117,6 +1122,57 @@ String ResourceLoaderBinary::recognize(Ref<FileAccess> p_f) {
return get_unicode_string();
}

String ResourceLoaderBinary::recognize_script_class(Ref<FileAccess> p_f) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@KoBeWi Sorry 🙏

Copy link
Member

@KoBeWi KoBeWi Jan 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

>:(

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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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()) {
Expand Down
4 changes: 4 additions & 0 deletions core/io/resource_format_binary.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -100,6 +101,7 @@ class ResourceLoaderBinary {
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);

Expand All @@ -113,6 +115,7 @@ class ResourceFormatLoaderBinary : public ResourceFormatLoader {
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);
Expand Down Expand Up @@ -165,6 +168,7 @@ class ResourceFormatSaverBinaryInstance {
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
Expand Down
20 changes: 20 additions & 0 deletions core/io/resource_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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);

Expand Down
3 changes: 3 additions & 0 deletions core/io/resource_loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class ResourceFormatLoader : public RefCounted {
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)
Expand All @@ -71,6 +72,7 @@ class ResourceFormatLoader : public RefCounted {
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);
Expand Down Expand Up @@ -175,6 +177,7 @@ class ResourceLoader {
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);
Expand Down
2 changes: 1 addition & 1 deletion core/object/script_language.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ class Script : public Resource {
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
Expand Down
1 change: 1 addition & 0 deletions core/object/script_language_extension.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class ScriptExtension : public Script {
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)

Expand Down
7 changes: 7 additions & 0 deletions doc/classes/ResourceFormatLoader.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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" />
Expand Down
26 changes: 24 additions & 2 deletions editor/editor_file_system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>();
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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;
Expand All @@ -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..
Expand Down Expand Up @@ -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;
Expand All @@ -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";
}
Expand Down Expand Up @@ -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";
}
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down
Loading