diff options
author | Marc Gilleron <marc.gilleron@gmail.com> | 2018-06-11 02:59:53 +0200 |
---|---|---|
committer | Marc Gilleron <marc.gilleron@gmail.com> | 2018-12-15 05:34:53 +0000 |
commit | 065e2670af53ae2f71b78d57f8a217b4539cbbe2 (patch) | |
tree | a6b802b74f6f7ebd2018b5a3d35061bdcb91eb9d /core/io | |
parent | ca28c455bfdc8408485c217c17f07011c0b43f64 (diff) |
Added basic support for custom resource savers and loaders
Diffstat (limited to 'core/io')
-rw-r--r-- | core/io/image_loader.h | 1 | ||||
-rw-r--r-- | core/io/resource_format_binary.h | 3 | ||||
-rw-r--r-- | core/io/resource_import.h | 2 | ||||
-rw-r--r-- | core/io/resource_loader.cpp | 196 | ||||
-rw-r--r-- | core/io/resource_loader.h | 28 | ||||
-rw-r--r-- | core/io/resource_saver.cpp | 150 | ||||
-rw-r--r-- | core/io/resource_saver.h | 25 | ||||
-rw-r--r-- | core/io/translation_loader_po.h | 1 |
8 files changed, 385 insertions, 21 deletions
diff --git a/core/io/image_loader.h b/core/io/image_loader.h index 7a58d46f93..15ee5e9ae1 100644 --- a/core/io/image_loader.h +++ b/core/io/image_loader.h @@ -88,6 +88,7 @@ public: }; class ResourceFormatLoaderImage : public ResourceFormatLoader { + GDCLASS(ResourceFormatLoaderImage, ResourceFormatLoader) public: virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h index 513252055f..e449ff216b 100644 --- a/core/io/resource_format_binary.h +++ b/core/io/resource_format_binary.h @@ -100,6 +100,7 @@ public: }; class ResourceFormatLoaderBinary : public ResourceFormatLoader { + GDCLASS(ResourceFormatLoaderBinary, ResourceFormatLoader) public: virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const; @@ -152,7 +153,7 @@ public: }; class ResourceFormatSaverBinary : public ResourceFormatSaver { - + GDCLASS(ResourceFormatSaverBinary, ResourceFormatSaver) public: static ResourceFormatSaverBinary *singleton; virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); diff --git a/core/io/resource_import.h b/core/io/resource_import.h index 53718bd789..ec66a422a3 100644 --- a/core/io/resource_import.h +++ b/core/io/resource_import.h @@ -37,6 +37,8 @@ class ResourceImporter; class ResourceFormatImporter : public ResourceFormatLoader { + GDCLASS(ResourceFormatImporter, ResourceFormatLoader) + struct PathAndType { String path; String type; diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 71b01aa94a..41f3b2935c 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -39,7 +39,7 @@ #include "core/translation.h" #include "core/variant_parser.h" -ResourceFormatLoader *ResourceLoader::loader[MAX_LOADERS]; +Ref<ResourceFormatLoader> ResourceLoader::loader[ResourceLoader::MAX_LOADERS]; int ResourceLoader::loader_count = 0; @@ -73,6 +73,25 @@ bool ResourceFormatLoader::recognize_path(const String &p_path, const String &p_ return false; } +bool ResourceFormatLoader::handles_type(const String &p_type) const { + + if (get_script_instance() && get_script_instance()->has_method("handles_type")) { + // I guess custom loaders for custom resources should use "Resource" + return get_script_instance()->call("handles_type", p_type); + } + + return false; +} + +String ResourceFormatLoader::get_resource_type(const String &p_path) const { + + if (get_script_instance() && get_script_instance()->has_method("get_resource_type")) { + return get_script_instance()->call("get_resource_type", p_path); + } + + return ""; +} + void ResourceFormatLoader::get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const { if (p_type == "" || handles_type(p_type)) @@ -129,9 +148,37 @@ bool ResourceFormatLoader::exists(const String &p_path) const { return FileAccess::exists(p_path); //by default just check file } +void ResourceFormatLoader::get_recognized_extensions(List<String> *p_extensions) const { + + if (get_script_instance() && get_script_instance()->has_method("get_recognized_extensions")) { + PoolStringArray exts = get_script_instance()->call("get_recognized_extensions"); + + { + PoolStringArray::Read r = exts.read(); + for (int i = 0; i < exts.size(); ++i) { + p_extensions->push_back(r[i]); + } + } + } +} + RES ResourceFormatLoader::load(const String &p_path, const String &p_original_path, Error *r_error) { - String path = p_path; + if (get_script_instance() && get_script_instance()->has_method("load")) { + Variant res = get_script_instance()->call("load", p_path, p_original_path); + + if (res.get_type() == Variant::INT) { + + if (r_error) + *r_error = (Error)res.operator int64_t(); + + } else { + + if (r_error) + *r_error = OK; + return res; + } + } //or this must be implemented Ref<ResourceInteractiveLoader> ril = load_interactive(p_path, p_original_path, r_error); @@ -160,7 +207,47 @@ RES ResourceFormatLoader::load(const String &p_path, const String &p_original_pa void ResourceFormatLoader::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) { - //do nothing by default + if (get_script_instance() && get_script_instance()->has_method("get_dependencies")) { + PoolStringArray deps = get_script_instance()->call("get_dependencies", p_path, p_add_types); + + { + PoolStringArray::Read r = deps.read(); + for (int i = 0; i < deps.size(); ++i) { + p_dependencies->push_back(r[i]); + } + } + } +} + +Error ResourceFormatLoader::rename_dependencies(const String &p_path, const Map<String, String> &p_map) { + + if (get_script_instance() && get_script_instance()->has_method("rename_dependencies")) { + + Dictionary deps_dict; + for (Map<String, String>::Element *E = p_map.front(); E; E = E->next()) { + deps_dict[E->key()] = E->value(); + } + + int64_t res = get_script_instance()->call("rename_dependencies", deps_dict); + return (Error)res; + } + + return OK; +} + +void ResourceFormatLoader::_bind_methods() { + + { + MethodInfo info = MethodInfo(Variant::NIL, "load", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "original_path")); + info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; + ClassDB::add_virtual_method(get_class_static(), info); + } + + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::POOL_STRING_ARRAY, "get_recognized_extensions")); + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "handles_type", PropertyInfo(Variant::STRING, "typename"))); + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_resource_type", PropertyInfo(Variant::STRING, "path"))); + ClassDB::add_virtual_method(get_class_static(), MethodInfo("get_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "add_types"))); + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "rename_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "renames"))); } /////////////////////////////////// @@ -348,9 +435,11 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_ return Ref<ResourceInteractiveLoader>(); } -void ResourceLoader::add_resource_format_loader(ResourceFormatLoader *p_format_loader, bool p_at_front) { +void ResourceLoader::add_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader, bool p_at_front) { + ERR_FAIL_COND(p_format_loader.is_null()); ERR_FAIL_COND(loader_count >= MAX_LOADERS); + if (p_at_front) { for (int i = loader_count; i > 0; i--) { loader[i] = loader[i - 1]; @@ -362,6 +451,27 @@ void ResourceLoader::add_resource_format_loader(ResourceFormatLoader *p_format_l } } +void ResourceLoader::remove_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader) { + + ERR_FAIL_COND(p_format_loader.is_null()); + + // Find loader + int i = 0; + for (; i < loader_count; ++i) { + if (loader[i] == p_format_loader) + break; + } + + ERR_FAIL_COND(i >= loader_count); // Not found + + // Shift next loaders up + for (; i < loader_count - 1; ++i) { + loader[i] = loader[i + 1]; + } + loader[loader_count - 1].unref(); + --loader_count; +} + int ResourceLoader::get_import_order(const String &p_path) { String path = _path_remap(p_path); @@ -645,6 +755,84 @@ void ResourceLoader::set_load_callback(ResourceLoadedCallback p_callback) { ResourceLoadedCallback ResourceLoader::_loaded_callback = NULL; +Ref<ResourceFormatLoader> ResourceLoader::_find_custom_resource_format_loader(String path) { + for (int i = 0; i < loader_count; ++i) { + if (loader[i]->get_script_instance() && loader[i]->get_script_instance()->get_script()->get_path() == path) { + return loader[i]; + } + } + return Ref<ResourceFormatLoader>(); +} + +bool ResourceLoader::add_custom_resource_format_loader(String script_path) { + + if (_find_custom_resource_format_loader(script_path).is_valid()) + return false; + + Ref<Resource> res = ResourceLoader::load(script_path); + ERR_FAIL_COND_V(res.is_null(), false); + ERR_FAIL_COND_V(!res->is_class("Script"), false); + + Ref<Script> s = res; + StringName ibt = s->get_instance_base_type(); + bool valid_type = ClassDB::is_parent_class(ibt, "ResourceFormatLoader"); + ERR_EXPLAIN("Script does not inherit a CustomResourceLoader: " + script_path); + ERR_FAIL_COND_V(!valid_type, false); + + Object *obj = ClassDB::instance(ibt); + + ERR_EXPLAIN("Cannot instance script as custom resource loader, expected 'ResourceFormatLoader' inheritance, got: " + String(ibt)); + ERR_FAIL_COND_V(obj == NULL, false); + + ResourceFormatLoader *crl = NULL; + crl = Object::cast_to<ResourceFormatLoader>(obj); + crl->set_script(s.get_ref_ptr()); + ResourceLoader::add_resource_format_loader(crl); + + return true; +} + +void ResourceLoader::remove_custom_resource_format_loader(String script_path) { + + Ref<ResourceFormatLoader> loader = _find_custom_resource_format_loader(script_path); + if (loader.is_valid()) + remove_resource_format_loader(loader); +} + +void ResourceLoader::add_custom_loaders() { + // Custom loaders registration exploits global class names + + String custom_loader_base_class = ResourceFormatLoader::get_class_static(); + + List<StringName> global_classes; + ScriptServer::get_global_class_list(&global_classes); + + for (List<StringName>::Element *E = global_classes.front(); E; E = E->next()) { + + StringName class_name = E->get(); + StringName base_class = ScriptServer::get_global_class_base(class_name); + + if (base_class == custom_loader_base_class) { + String path = ScriptServer::get_global_class_path(class_name); + add_custom_resource_format_loader(path); + } + } +} + +void ResourceLoader::remove_custom_loaders() { + + Vector<Ref<ResourceFormatLoader> > custom_loaders; + for (int i = 0; i < loader_count; ++i) { + if (loader[i]->get_script_instance()) { + custom_loaders.push_back(loader[i]); + } + } + + for (int i = 0; i < custom_loaders.size(); ++i) { + remove_resource_format_loader(custom_loaders[i]); + } +} + ResourceLoadErrorNotify ResourceLoader::err_notify = NULL; void *ResourceLoader::err_notify_ud = NULL; diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h index 7ade4a2dfc..5e1ecfd230 100644 --- a/core/io/resource_loader.h +++ b/core/io/resource_loader.h @@ -56,18 +56,24 @@ public: ResourceInteractiveLoader() {} }; -class ResourceFormatLoader { +class ResourceFormatLoader : public Reference { + + GDCLASS(ResourceFormatLoader, Reference) + +protected: + static void _bind_methods(); + public: virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual bool exists(const String &p_path) const; - virtual void get_recognized_extensions(List<String> *p_extensions) const = 0; + virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const; virtual bool recognize_path(const String &p_path, const String &p_for_type = String()) const; - virtual bool handles_type(const String &p_type) const = 0; - virtual String get_resource_type(const String &p_path) const = 0; + virtual bool handles_type(const String &p_type) const; + virtual String get_resource_type(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 Map<String, String> &p_map) { return OK; } + virtual Error rename_dependencies(const String &p_path, const Map<String, String> &p_map); virtual bool is_import_valid(const String &p_path) const { return true; } virtual int get_import_order(const String &p_path) const { return 0; } @@ -86,7 +92,7 @@ class ResourceLoader { MAX_LOADERS = 64 }; - static ResourceFormatLoader *loader[MAX_LOADERS]; + static Ref<ResourceFormatLoader> loader[MAX_LOADERS]; static int loader_count; static bool timestamp_on_load; @@ -109,13 +115,16 @@ class ResourceLoader { static ResourceLoadedCallback _loaded_callback; + static Ref<ResourceFormatLoader> _find_custom_resource_format_loader(String path); + public: static Ref<ResourceInteractiveLoader> load_interactive(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false, Error *r_error = NULL); static RES load(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false, Error *r_error = NULL); static bool exists(const String &p_path, const String &p_type_hint = ""); static void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions); - static void add_resource_format_loader(ResourceFormatLoader *p_format_loader, bool p_at_front = false); + static void add_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader, bool p_at_front = false); + static void remove_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader); static String get_resource_type(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 Map<String, String> &p_map); @@ -155,6 +164,11 @@ public: static void set_load_callback(ResourceLoadedCallback p_callback); static ResourceLoaderImport import; + + static bool add_custom_resource_format_loader(String script_path); + static void remove_custom_resource_format_loader(String script_path); + static void add_custom_loaders(); + static void remove_custom_loaders(); }; #endif diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp index 097e81e308..af726d9e2d 100644 --- a/core/io/resource_saver.cpp +++ b/core/io/resource_saver.cpp @@ -29,18 +29,62 @@ /*************************************************************************/ #include "resource_saver.h" - #include "core/io/resource_loader.h" #include "core/os/file_access.h" #include "core/project_settings.h" #include "core/script_language.h" -ResourceFormatSaver *ResourceSaver::saver[MAX_SAVERS]; +Ref<ResourceFormatSaver> ResourceSaver::saver[MAX_SAVERS]; int ResourceSaver::saver_count = 0; bool ResourceSaver::timestamp_on_save = false; ResourceSavedCallback ResourceSaver::save_callback = 0; +Error ResourceFormatSaver::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { + + if (get_script_instance() && get_script_instance()->has_method("save")) { + return (Error)get_script_instance()->call("save", p_path, p_resource, p_flags).operator int64_t(); + } + + return ERR_METHOD_NOT_FOUND; +} + +bool ResourceFormatSaver::recognize(const RES &p_resource) const { + + if (get_script_instance() && get_script_instance()->has_method("recognize")) { + return get_script_instance()->call("recognize", p_resource); + } + + return false; +} + +void ResourceFormatSaver::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const { + + if (get_script_instance() && get_script_instance()->has_method("get_recognized_extensions")) { + PoolStringArray exts = get_script_instance()->call("get_recognized_extensions", p_resource); + + { + PoolStringArray::Read r = exts.read(); + for (int i = 0; i < exts.size(); ++i) { + p_extensions->push_back(r[i]); + } + } + } +} + +void ResourceFormatSaver::_bind_methods() { + + { + PropertyInfo arg0 = PropertyInfo(Variant::STRING, "path"); + PropertyInfo arg1 = PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"); + PropertyInfo arg2 = PropertyInfo(Variant::INT, "flags"); + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "save", arg0, arg1, arg2)); + } + + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::POOL_STRING_ARRAY, "get_recognized_extensions", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"))); + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "recognize", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"))); +} + Error ResourceSaver::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { String extension = p_path.get_extension(); @@ -113,8 +157,9 @@ void ResourceSaver::get_recognized_extensions(const RES &p_resource, List<String } } -void ResourceSaver::add_resource_format_saver(ResourceFormatSaver *p_format_saver, bool p_at_front) { +void ResourceSaver::add_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver, bool p_at_front) { + ERR_FAIL_COND(p_format_saver.is_null()); ERR_FAIL_COND(saver_count >= MAX_SAVERS); if (p_at_front) { @@ -127,3 +172,102 @@ void ResourceSaver::add_resource_format_saver(ResourceFormatSaver *p_format_save saver[saver_count++] = p_format_saver; } } + +void ResourceSaver::remove_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver) { + + ERR_FAIL_COND(p_format_saver.is_null()); + + // Find saver + int i = 0; + for (; i < saver_count; ++i) { + if (saver[i] == p_format_saver) + break; + } + + ERR_FAIL_COND(i >= saver_count); // Not found + + // Shift next savers up + for (; i < saver_count - 1; ++i) { + saver[i] = saver[i + 1]; + } + saver[saver_count - 1].unref(); + --saver_count; +} + +Ref<ResourceFormatSaver> ResourceSaver::_find_custom_resource_format_saver(String path) { + for (int i = 0; i < saver_count; ++i) { + if (saver[i]->get_script_instance() && saver[i]->get_script_instance()->get_script()->get_path() == path) { + return saver[i]; + } + } + return Ref<ResourceFormatSaver>(); +} + +bool ResourceSaver::add_custom_resource_format_saver(String script_path) { + + if (_find_custom_resource_format_saver(script_path).is_valid()) + return false; + + Ref<Resource> res = ResourceLoader::load(script_path); + ERR_FAIL_COND_V(res.is_null(), false); + ERR_FAIL_COND_V(!res->is_class("Script"), false); + + Ref<Script> s = res; + StringName ibt = s->get_instance_base_type(); + bool valid_type = ClassDB::is_parent_class(ibt, "ResourceFormatSaver"); + ERR_EXPLAIN("Script does not inherit a CustomResourceSaver: " + script_path); + ERR_FAIL_COND_V(!valid_type, false); + + Object *obj = ClassDB::instance(ibt); + + ERR_EXPLAIN("Cannot instance script as custom resource saver, expected 'ResourceFormatSaver' inheritance, got: " + String(ibt)); + ERR_FAIL_COND_V(obj == NULL, false); + + ResourceFormatSaver *crl = NULL; + crl = Object::cast_to<ResourceFormatSaver>(obj); + crl->set_script(s.get_ref_ptr()); + ResourceSaver::add_resource_format_saver(crl); + + return true; +} + +void ResourceSaver::remove_custom_resource_format_saver(String script_path) { + + Ref<ResourceFormatSaver> saver = _find_custom_resource_format_saver(script_path); + if (saver.is_valid()) + remove_resource_format_saver(saver); +} + +void ResourceSaver::add_custom_savers() { + // Custom resource savers exploits global class names + + String custom_saver_base_class = ResourceFormatSaver::get_class_static(); + + List<StringName> global_classes; + ScriptServer::get_global_class_list(&global_classes); + + for (List<StringName>::Element *E = global_classes.front(); E; E = E->next()) { + + StringName class_name = E->get(); + StringName base_class = ScriptServer::get_global_class_base(class_name); + + if (base_class == custom_saver_base_class) { + String path = ScriptServer::get_global_class_path(class_name); + add_custom_resource_format_saver(path); + } + } +} + +void ResourceSaver::remove_custom_savers() { + + Vector<Ref<ResourceFormatSaver> > custom_savers; + for (int i = 0; i < saver_count; ++i) { + if (saver[i]->get_script_instance()) { + custom_savers.push_back(saver[i]); + } + } + + for (int i = 0; i < custom_savers.size(); ++i) { + remove_resource_format_saver(custom_savers[i]); + } +} diff --git a/core/io/resource_saver.h b/core/io/resource_saver.h index 6134d9db57..38b59bdb53 100644 --- a/core/io/resource_saver.h +++ b/core/io/resource_saver.h @@ -37,11 +37,16 @@ @author Juan Linietsky <reduzio@gmail.com> */ -class ResourceFormatSaver { +class ResourceFormatSaver : public Reference { + GDCLASS(ResourceFormatSaver, Reference) + +protected: + static void _bind_methods(); + public: - virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0) = 0; - virtual bool recognize(const RES &p_resource) const = 0; - virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const = 0; + virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); + virtual bool recognize(const RES &p_resource) const; + virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const; virtual ~ResourceFormatSaver() {} }; @@ -54,11 +59,13 @@ class ResourceSaver { MAX_SAVERS = 64 }; - static ResourceFormatSaver *saver[MAX_SAVERS]; + static Ref<ResourceFormatSaver> saver[MAX_SAVERS]; static int saver_count; static bool timestamp_on_save; static ResourceSavedCallback save_callback; + static Ref<ResourceFormatSaver> _find_custom_resource_format_saver(String path); + public: enum SaverFlags { @@ -73,10 +80,16 @@ public: static Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); static void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions); - static void add_resource_format_saver(ResourceFormatSaver *p_format_saver, bool p_at_front = false); + static void add_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver, bool p_at_front = false); + static void remove_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver); static void set_timestamp_on_save(bool p_timestamp) { timestamp_on_save = p_timestamp; } static void set_save_callback(ResourceSavedCallback p_callback); + + static bool add_custom_resource_format_saver(String script_path); + static void remove_custom_resource_format_saver(String script_path); + static void add_custom_savers(); + static void remove_custom_savers(); }; #endif diff --git a/core/io/translation_loader_po.h b/core/io/translation_loader_po.h index 670a9fdd7e..9543307cb5 100644 --- a/core/io/translation_loader_po.h +++ b/core/io/translation_loader_po.h @@ -36,6 +36,7 @@ #include "core/translation.h" class TranslationLoaderPO : public ResourceFormatLoader { + GDCLASS(TranslationLoaderPO, ResourceFormatLoader) public: static RES load_translation(FileAccess *f, Error *r_error, const String &p_path = String()); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); |