From b60208a20613e262ea29a1f55d48bb1531cfed8b Mon Sep 17 00:00:00 2001 From: Juan Date: Thu, 5 Sep 2024 08:52:37 +0200 Subject: [PATCH] Provide a reliable way to see original resources in a directory When exporting a project, resources are often moved, converted or remapped (source import files are gone, text scenes are converted to binary, etc). This new function allows to list a directory and obtain the actual original resource files. Example ```GDScript var resources = ResourceLoader.list_directory("res://images") print(resources) ``` Result will be something like: ``` ["image1.png","image2.png","image3.png"] ``` instead of ``` ["image1.png.import","image2.png.import","image3.png.import"] ``` --- core/core_bind.cpp | 5 ++++ core/core_bind.h | 2 ++ core/io/resource_loader.cpp | 49 ++++++++++++++++++++++++++++++++++ core/io/resource_loader.h | 2 ++ doc/classes/DirAccess.xml | 1 + doc/classes/ResourceLoader.xml | 7 +++++ 6 files changed, 66 insertions(+) diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 4172793f9d8f..676cc5ef0bd8 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -129,6 +129,10 @@ ResourceUID::ID ResourceLoader::get_resource_uid(const String &p_path) { return ::ResourceLoader::get_resource_uid(p_path); } +Vector ResourceLoader::list_directory(const String &p_directory) { + return ::ResourceLoader::list_directory(p_directory); +} + void ResourceLoader::_bind_methods() { ClassDB::bind_method(D_METHOD("load_threaded_request", "path", "type_hint", "use_sub_threads", "cache_mode"), &ResourceLoader::load_threaded_request, DEFVAL(""), DEFVAL(false), DEFVAL(CACHE_MODE_REUSE)); ClassDB::bind_method(D_METHOD("load_threaded_get_status", "path", "progress"), &ResourceLoader::load_threaded_get_status, DEFVAL(Array())); @@ -144,6 +148,7 @@ void ResourceLoader::_bind_methods() { ClassDB::bind_method(D_METHOD("get_cached_ref", "path"), &ResourceLoader::get_cached_ref); ClassDB::bind_method(D_METHOD("exists", "path", "type_hint"), &ResourceLoader::exists, DEFVAL("")); ClassDB::bind_method(D_METHOD("get_resource_uid", "path"), &ResourceLoader::get_resource_uid); + ClassDB::bind_method(D_METHOD("list_directory", "directory_path"), &ResourceLoader::list_directory); BIND_ENUM_CONSTANT(THREAD_LOAD_INVALID_RESOURCE); BIND_ENUM_CONSTANT(THREAD_LOAD_IN_PROGRESS); diff --git a/core/core_bind.h b/core/core_bind.h index 122963e634dc..7e5f7e6f8342 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -87,6 +87,8 @@ class ResourceLoader : public Object { bool exists(const String &p_path, const String &p_type_hint = ""); ResourceUID::ID get_resource_uid(const String &p_path); + Vector list_directory(const String &p_directory); + ResourceLoader() { singleton = this; } }; diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 7cf101b0de5e..38d3a048e0a7 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -31,6 +31,7 @@ #include "resource_loader.h" #include "core/config/project_settings.h" +#include "core/io/dir_access.h" #include "core/io/file_access.h" #include "core/io/resource_importer.h" #include "core/object/script_language.h" @@ -39,6 +40,7 @@ #include "core/os/safe_binary_mutex.h" #include "core/string/print_string.h" #include "core/string/translation_server.h" +#include "core/templates/rb_set.h" #include "core/variant/variant_parser.h" #include "servers/rendering_server.h" @@ -1354,6 +1356,53 @@ bool ResourceLoader::is_cleaning_tasks() { return cleaning_tasks; } +Vector ResourceLoader::list_directory(const String &p_directory) { + RBSet files_found; + Ref dir = DirAccess::open(p_directory); + if (dir.is_null()) { + return Vector(); + } + + Error err = dir->list_dir_begin(); + if (err != OK) { + return Vector(); + } + + String d = dir->get_next(); + while (d != String()) { + bool recognized = false; + if (dir->current_is_dir()) { + d += "/"; + recognized = true; + } else { + if (d.ends_with(".import") || d.ends_with(".remap")) { + int idx = d.rfind("."); + d = d.substr(0, idx); + } + + String full_path = p_directory.path_join(d); + // Try all loaders and pick the first match for the type hint + for (int i = 0; i < loader_count; i++) { + if (loader[i]->recognize_path(full_path)) { + recognized = true; + break; + } + } + } + if (recognized) { + files_found.insert(d); + } + d = dir->get_next(); + } + + Vector ret; + for (const String &f : files_found) { + ret.push_back(f); + } + + return ret; +} + void ResourceLoader::initialize() {} void ResourceLoader::finalize() {} diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h index f75bf019fb54..244f280fb1ce 100644 --- a/core/io/resource_loader.h +++ b/core/io/resource_loader.h @@ -288,6 +288,8 @@ class ResourceLoader { static bool is_cleaning_tasks(); + static Vector list_directory(const String &p_directory); + static void initialize(); static void finalize(); }; diff --git a/doc/classes/DirAccess.xml b/doc/classes/DirAccess.xml index 9c71addf0c5d..dcd2d527e2f6 100644 --- a/doc/classes/DirAccess.xml +++ b/doc/classes/DirAccess.xml @@ -60,6 +60,7 @@ } [/csharp] [/codeblocks] + Keep in mind that file names may change or be remapped after export. If you want to see the actual resource file list as it appears in the editor, use [method ResourceLoader.list_directory] instead. $DOCS_URL/tutorials/scripting/filesystem.html diff --git a/doc/classes/ResourceLoader.xml b/doc/classes/ResourceLoader.xml index 56c3208fc308..1e2c0efafab9 100644 --- a/doc/classes/ResourceLoader.xml +++ b/doc/classes/ResourceLoader.xml @@ -74,6 +74,13 @@ Once a resource has been loaded by the engine, it is cached in memory for faster access, and future calls to the [method load] method will use the cached version. The cached resource can be overridden by using [method Resource.take_over_path] on a new resource for that same path. + + + + + Lists a directory (as example: "res://assets/enemies"), returning all resources contained within. The resource files are the original file names as visible in the editor before exporting. + +