diff options
-rw-r--r-- | modules/dlscript/dl_script.cpp | 392 | ||||
-rw-r--r-- | modules/dlscript/dl_script.h | 66 |
2 files changed, 295 insertions, 163 deletions
diff --git a/modules/dlscript/dl_script.cpp b/modules/dlscript/dl_script.cpp index b0c3bc2bfd..fa082d7b94 100644 --- a/modules/dlscript/dl_script.cpp +++ b/modules/dlscript/dl_script.cpp @@ -35,17 +35,114 @@ #include "os/file_access.h" #include "os/os.h" +#include "scene/main/scene_main_loop.h" #include "scene/resources/scene_format_text.h" -#ifdef TOOLS_ENABLED -// #include "editor/editor_import_export.h" -#endif - #if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED) #include "api_generator.h" #endif +#ifdef TOOLS_ENABLED +#include "editor/editor_node.h" +#endif + +Error NativeLibrary::initialize(NativeLibrary *&p_native_lib, const StringName p_path) { + + if (DLScriptLanguage::get_singleton()->initialized_libraries.has(p_path)) { + p_native_lib = DLScriptLanguage::get_singleton()->initialized_libraries[p_path]; + return OK; + } + + NativeLibrary *lib = memnew(NativeLibrary); + lib->path = p_path; + + p_native_lib = lib; + + // Open the file + + Error error; + error = OS::get_singleton()->open_dynamic_library(p_path, lib->handle); + if (error) return error; + ERR_FAIL_COND_V(!lib->handle, ERR_BUG); + + // Get the method + + void *library_init; + error = OS::get_singleton()->get_dynamic_library_symbol_handle(lib->handle, DLScriptLanguage::get_init_symbol_name(), library_init); + if (error) return error; + ERR_FAIL_COND_V(!library_init, ERR_BUG); + + void (*library_init_fpointer)(godot_dlscript_init_options *) = (void (*)(godot_dlscript_init_options *))library_init; + + godot_dlscript_init_options options; + + options.in_editor = SceneTree::get_singleton()->is_editor_hint(); + /* + options.core_api_hash = ClassDB::get_api_hash(ClassDB::API_CORE); + options.editor_api_hash = ClassDB::get_api_hash(ClassDB::API_EDITOR); + options.no_api_hash = ClassDB::get_api_hash(ClassDB::API_NONE); + */ + + library_init_fpointer(&options); // Catch errors? + + DLScriptLanguage::get_singleton()->initialized_libraries[p_path] = lib; + + return OK; +} + +Error NativeLibrary::terminate(NativeLibrary *&p_native_lib) { + + if (!DLScriptLanguage::get_singleton()->initialized_libraries.has(p_native_lib->path)) { + OS::get_singleton()->close_dynamic_library(p_native_lib->handle); + p_native_lib->handle = 0; + return OK; + } + + Error error = OK; + void *library_terminate; + error = OS::get_singleton()->get_dynamic_library_symbol_handle(p_native_lib->handle, DLScriptLanguage::get_terminate_symbol_name(), library_terminate); + if (error) + return OK; // no terminate? okay, not that important lol + + void (*library_terminate_pointer)(godot_dlscript_terminate_options *) = (void (*)(godot_dlscript_terminate_options *))library_terminate; + + godot_dlscript_terminate_options options; + options.in_editor = SceneTree::get_singleton()->is_editor_hint(); + + library_terminate_pointer(&options); + + DLScriptLanguage::get_singleton()->initialized_libraries.erase(p_native_lib->path); + + OS::get_singleton()->close_dynamic_library(p_native_lib->handle); + p_native_lib->handle = 0; + + return OK; +} + // Script +#ifdef TOOLS_ENABLED + +void DLScript::_update_placeholder(PlaceHolderScriptInstance *p_placeholder) { + + List<PropertyInfo> pinfo; + Map<StringName, Variant> values; + + for (Map<StringName, DLScriptData::Property>::Element *E = script_data->properties.front(); E; E = E->next()) { + PropertyInfo p = E->get().info; + p.name = String(E->key()); + pinfo.push_back(p); + values[p.name] = E->get().default_value; + } + + p_placeholder->update(pinfo, values); +} + +void DLScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) { + + placeholders.erase(p_placeholder); +} + +#endif bool DLScript::can_instance() const { #ifdef DLSCRIPT_EDITOR_FEATURES @@ -92,14 +189,11 @@ ScriptInstance *DLScript::instance_create(Object *p_this) { PlaceHolderScriptInstance *sins = memnew(PlaceHolderScriptInstance(DLScriptLanguage::singleton, Ref<Script>((Script *)this), p_this)); placeholders.insert(sins); - List<PropertyInfo> pinfo; - Map<StringName, Variant> values; - if (!library.is_valid()) return sins; - if (!library->library_handle) { - Error err = library->_initialize_handle(true); + if (!library->native_library) { + Error err = library->_initialize(); if (err != OK) { return sins; } @@ -108,20 +202,11 @@ ScriptInstance *DLScript::instance_create(Object *p_this) { if (!script_data) { script_data = library->get_script_data(script_name); } - if (script_data) + if (script_data && script_data->create_func.create_func) { script_data->create_func.create_func((godot_object *)p_this, script_data->create_func.method_data); - - if (script_data) { - for (Map<StringName, DLScriptData::Property>::Element *E = script_data->properties.front(); E; E = E->next()) { - - PropertyInfo p = E->get().info; - p.name = String(E->key()); - pinfo.push_back(p); - values[p.name] = E->get().default_value; - } } - sins->update(pinfo, values); + _update_placeholder(sins); return sins; } @@ -321,10 +406,10 @@ void DLScript::set_library(Ref<DLLibrary> p_library) { return; #endif if (library.is_valid()) { - Error initalize_status = library->_initialize_handle(!ScriptServer::is_scripting_enabled()); + Error initalize_status = library->_initialize(); ERR_FAIL_COND(initalize_status != OK); if (script_name) { - script_data = library->get_script_data(script_name); + script_data = library->native_library->scripts[script_name]; ERR_FAIL_COND(!script_data); } } @@ -338,8 +423,15 @@ void DLScript::set_script_name(StringName p_script_name) { script_name = p_script_name; if (library.is_valid()) { - script_data = library->get_script_data(script_name); - ERR_FAIL_COND(!script_data); +#ifdef DLSCRIPT_EDITOR_FEATURES + if (!library->native_library) { + library->_initialize(); + } +#endif + if (library->native_library) { + script_data = library->get_script_data(script_name); + ERR_FAIL_COND(!script_data); + } } } @@ -355,10 +447,12 @@ void DLScript::_bind_methods() { DLScript::DLScript() { script_data = NULL; + DLScriptLanguage::get_singleton()->script_list.insert(this); } DLScript::~DLScript() { //hmm + DLScriptLanguage::get_singleton()->script_list.erase(this); } // Library @@ -401,11 +495,9 @@ String DLLibrary::get_platform_file(StringName p_platform) const { } } -Error DLLibrary::_initialize_handle(bool p_in_editor) { +Error DLLibrary::_initialize() { _THREAD_SAFE_METHOD_ - void *_library_handle; - // Get the file const String platform_name = OS::get_singleton()->get_name(); @@ -435,90 +527,62 @@ Error DLLibrary::_initialize_handle(bool p_in_editor) { } ERR_FAIL_COND_V(platform_file == "", ERR_DOES_NOT_EXIST); - library_path = GlobalConfig::get_singleton()->globalize_path(platform_file); - - if (DLScriptLanguage::get_singleton()->is_library_initialized(library_path)) { - *this = *DLScriptLanguage::get_singleton()->get_library_dllibrary(library_path); - return OK; - } - - // Open the file - - Error error; - error = OS::get_singleton()->open_dynamic_library(library_path, _library_handle); - if (error) return error; - ERR_FAIL_COND_V(!_library_handle, ERR_BUG); - - // Get the method - - void *library_init; - error = OS::get_singleton()->get_dynamic_library_symbol_handle(_library_handle, DLScriptLanguage::get_init_symbol_name(), library_init); - if (error) return error; - ERR_FAIL_COND_V(!library_init, ERR_BUG); + StringName path = GlobalConfig::get_singleton()->globalize_path(platform_file); DLLibrary::currently_initialized_library = this; - void (*library_init_fpointer)(godot_dlscript_init_options *) = (void (*)(godot_dlscript_init_options *))library_init; - - godot_dlscript_init_options options; - - options.in_editor = p_in_editor; - options.core_api_hash = ClassDB::get_api_hash(ClassDB::API_CORE); - options.editor_api_hash = ClassDB::get_api_hash(ClassDB::API_EDITOR); - options.no_api_hash = ClassDB::get_api_hash(ClassDB::API_NONE); - - library_init_fpointer(&options); // Catch errors? - /*{ - ERR_EXPLAIN("Couldn't initialize library"); - ERR_FAIL_V(ERR_SCRIPT_FAILED); - }*/ + Error ret = NativeLibrary::initialize(native_library, path); + native_library->dllib = this; DLLibrary::currently_initialized_library = NULL; - library_handle = _library_handle; - - DLScriptLanguage::get_singleton()->set_library_initialized(library_path, this); - return OK; + return ret; } -Error DLLibrary::_free_handle(bool p_in_editor) { - ERR_FAIL_COND_V(!library_handle, ERR_BUG); +Error DLLibrary::_terminate() { + ERR_FAIL_COND_V(!native_library, ERR_BUG); + ERR_FAIL_COND_V(!native_library->handle, ERR_BUG); - if (!DLScriptLanguage::get_singleton()->is_library_initialized(library_path)) { - OS::get_singleton()->close_dynamic_library(library_handle); - library_handle = 0; - return OK; - } + // de-init stuff - Error error = OK; - void *library_terminate; - error = OS::get_singleton()->get_dynamic_library_symbol_handle(library_handle, DLScriptLanguage::get_terminate_symbol_name(), library_terminate); - if (error) - return OK; // no terminate? okay, not that important lol - - void (*library_terminate_pointer)(godot_dlscript_terminate_options *) = (void (*)(godot_dlscript_terminate_options *))library_terminate; + for (Map<StringName, DLScriptData *>::Element *E = native_library->scripts.front(); E; E = E->next()) { + for (Map<StringName, DLScriptData::Method>::Element *M = E->get()->methods.front(); M; M = M->next()) { + if (M->get().method.free_func) { + M->get().method.free_func(M->get().method.method_data); + } + } + if (E->get()->create_func.free_func) { + E->get()->create_func.free_func(E->get()->create_func.method_data); + } + if (E->get()->destroy_func.free_func) { + E->get()->destroy_func.free_func(E->get()->destroy_func.method_data); + } - godot_dlscript_terminate_options options; - options.in_editor = p_in_editor; + for (Set<DLScript *>::Element *S = DLScriptLanguage::get_singleton()->script_list.front(); S; S = S->next()) { + if (S->get()->script_data == E->get()) { + S->get()->script_data = NULL; + } + } - library_terminate_pointer(&options); + memdelete(E->get()); + } - DLScriptLanguage::get_singleton()->set_library_uninitialized(library_path); + Error ret = NativeLibrary::terminate(native_library); - OS::get_singleton()->close_dynamic_library(library_handle); - library_handle = 0; + native_library->scripts.clear(); - return OK; + return ret; } void DLLibrary::_register_script(const StringName p_name, const StringName p_base, godot_instance_create_func p_instance_func, godot_instance_destroy_func p_destroy_func) { - ERR_FAIL_COND(scripts.has(p_name)); + ERR_FAIL_COND(!native_library); + ERR_FAIL_COND(native_library->scripts.has(p_name)); DLScriptData *s = memnew(DLScriptData); s->base = p_base; s->create_func = p_instance_func; s->destroy_func = p_destroy_func; - Map<StringName, DLScriptData *>::Element *E = scripts.find(p_base); + Map<StringName, DLScriptData *>::Element *E = native_library->scripts.find(p_base); if (E) { s->base_data = E->get(); s->base_native_type = s->base_data->base_native_type; @@ -531,18 +595,19 @@ void DLLibrary::_register_script(const StringName p_name, const StringName p_bas s->base_native_type = p_base; } - scripts.insert(p_name, s); + native_library->scripts.insert(p_name, s); } void DLLibrary::_register_tool_script(const StringName p_name, const StringName p_base, godot_instance_create_func p_instance_func, godot_instance_destroy_func p_destroy_func) { - ERR_FAIL_COND(scripts.has(p_name)); + ERR_FAIL_COND(!native_library); + ERR_FAIL_COND(native_library->scripts.has(p_name)); DLScriptData *s = memnew(DLScriptData); s->base = p_base; s->create_func = p_instance_func; s->destroy_func = p_destroy_func; s->is_tool = true; - Map<StringName, DLScriptData *>::Element *E = scripts.find(p_base); + Map<StringName, DLScriptData *>::Element *E = native_library->scripts.find(p_base); if (E) { s->base_data = E->get(); s->base_native_type = s->base_data->base_native_type; @@ -555,22 +620,24 @@ void DLLibrary::_register_tool_script(const StringName p_name, const StringName s->base_native_type = p_base; } - scripts.insert(p_name, s); + native_library->scripts.insert(p_name, s); } void DLLibrary::_register_script_method(const StringName p_name, const StringName p_method, godot_method_attributes p_attr, godot_instance_method p_func, MethodInfo p_info) { - ERR_FAIL_COND(!scripts.has(p_name)); + ERR_FAIL_COND(!native_library); + ERR_FAIL_COND(!native_library->scripts.has(p_name)); p_info.name = p_method; DLScriptData::Method method; method = DLScriptData::Method(p_func, p_info, p_attr.rpc_type); - scripts[p_name]->methods.insert(p_method, method); + native_library->scripts[p_name]->methods.insert(p_method, method); } void DLLibrary::_register_script_property(const StringName p_name, const String p_path, godot_property_attributes *p_attr, godot_property_set_func p_setter, godot_property_get_func p_getter) { - ERR_FAIL_COND(!scripts.has(p_name)); + ERR_FAIL_COND(!native_library); + ERR_FAIL_COND(!native_library->scripts.has(p_name)); DLScriptData::Property p; @@ -583,11 +650,12 @@ void DLLibrary::_register_script_property(const StringName p_name, const String p = DLScriptData::Property(p_setter, p_getter, pi, *(Variant *)&p_attr->default_value, p_attr->rset_type); } - scripts[p_name]->properties.insert(p_path, p); + native_library->scripts[p_name]->properties.insert(p_path, p); } void DLLibrary::_register_script_signal(const StringName p_name, const godot_signal *p_signal) { - ERR_FAIL_COND(!scripts.has(p_name)); + ERR_FAIL_COND(!native_library); + ERR_FAIL_COND(!native_library->scripts.has(p_name)); ERR_FAIL_COND(!p_signal); DLScriptData::Signal signal; @@ -627,19 +695,15 @@ void DLLibrary::_register_script_signal(const StringName p_name, const godot_sig signal.signal.default_arguments = default_arguments; } - scripts[p_name]->signals_.insert(*(String *)&p_signal->name, signal); + native_library->scripts[p_name]->signals_.insert(*(String *)&p_signal->name, signal); } DLScriptData *DLLibrary::get_script_data(const StringName p_name) { + ERR_FAIL_COND_V(!native_library, NULL); - if (!scripts.has(p_name)) { - if (DLScriptLanguage::get_singleton()->is_library_initialized(library_path)) { - _update_library(*DLScriptLanguage::get_singleton()->get_library_dllibrary(library_path)); - } - ERR_FAIL_COND_V(!scripts.has(p_name), NULL); - } + ERR_FAIL_COND_V(!native_library->scripts.has(p_name), NULL); - return scripts[p_name]; + return native_library->scripts[p_name]; } bool DLLibrary::_set(const StringName &p_name, const Variant &p_value) { @@ -668,6 +732,9 @@ void DLLibrary::_get_property_list(List<PropertyInfo> *p_list) const { List<StringName> ep; // ep.push_back("X11"); // EditorImportExport::get_singleton()->get_export_platforms(&ep); + + // @Todo + // get export platforms with the new export system somehow. for (List<StringName>::Element *E = ep.front(); E; E = E->next()) { registered_platform_names.insert(String(E->get()).to_lower()); } @@ -712,26 +779,17 @@ void DLLibrary::_bind_methods() { } DLLibrary::DLLibrary() { - library_handle = NULL; + native_library = NULL; } DLLibrary::~DLLibrary() { - for (Map<StringName, DLScriptData *>::Element *E = scripts.front(); E; E = E->next()) { - for (Map<StringName, DLScriptData::Method>::Element *M = E->get()->methods.front(); M; M = M->next()) { - if (M->get().method.free_func) { - M->get().method.free_func(M->get().method.method_data); - } - } - memdelete(E->get()); + if (!native_library) { + return; } - if (library_handle) { - bool in_editor = false; -#ifdef TOOLS_ENABLED - in_editor = !ScriptServer::is_scripting_enabled(); -#endif - _free_handle(in_editor); + if (native_library->handle) { + _terminate(); } } @@ -907,24 +965,11 @@ String DLScriptLanguage::get_name() const { return "DLScript"; } -bool DLScriptLanguage::is_library_initialized(const String &p_path) { - - return initialized_libraries.has(p_path); -} - -void DLScriptLanguage::set_library_initialized(const String &p_path, DLLibrary *p_dllibrary) { - - initialized_libraries[p_path] = p_dllibrary; -} - -DLLibrary *DLScriptLanguage::get_library_dllibrary(const String &p_path) { - - return initialized_libraries[p_path]; -} - -void DLScriptLanguage::set_library_uninitialized(const String &p_path) { - - initialized_libraries.erase(p_path); +void _add_reload_node() { +#ifdef TOOLS_ENABLED + DLReloadNode *rn = memnew(DLReloadNode); + EditorNode::get_singleton()->add_child(rn); +#endif } void DLScriptLanguage::init() { @@ -946,6 +991,12 @@ void DLScriptLanguage::init() { } } #endif + +#ifdef TOOLS_ENABLED + // if (SceneTree::get_singleton()->is_editor_hint()) { + EditorNode::add_init_callback(&_add_reload_node); +// } +#endif } String DLScriptLanguage::get_type() const { @@ -1080,13 +1131,78 @@ DLScriptLanguage::DLScriptLanguage() { ERR_FAIL_COND(singleton); strings._notification = StringName("_notification"); singleton = this; - initialized_libraries = Map<String, DLLibrary *>(); + initialized_libraries = Map<StringName, NativeLibrary *>(); } DLScriptLanguage::~DLScriptLanguage() { singleton = NULL; } +// DLReloadNode + +void DLReloadNode::_bind_methods() { + ClassDB::bind_method("_notification", &DLReloadNode::_notification); +} + +void DLReloadNode::_notification(int p_what) { +#ifdef TOOLS_ENABLED + + switch (p_what) { + case MainLoop::NOTIFICATION_WM_FOCUS_IN: { + + // break; // For now. + + Set<NativeLibrary *> libs_to_reload; + + for (Map<StringName, NativeLibrary *>::Element *L = DLScriptLanguage::get_singleton()->initialized_libraries.front(); L; L = L->next()) { + // check if file got modified at all + // @Todo + + libs_to_reload.insert(L->get()); + } + + for (Set<NativeLibrary *>::Element *L = libs_to_reload.front(); L; L = L->next()) { + + DLLibrary *lib = L->get()->dllib; + + lib->_terminate(); + lib->_initialize(); + + // update placeholders (if any) + + DLScript *script = NULL; + + for (Set<DLScript *>::Element *S = DLScriptLanguage::get_singleton()->script_list.front(); S; S = S->next()) { + if (lib->native_library->scripts.has(S->get()->get_script_name())) { + script = S->get(); + script->script_data = lib->get_script_data(script->get_script_name()); + break; + } + } + + if (script == NULL) { + // new class, cool. Nothing to do here + continue; + } + + if (script->placeholders.size() == 0) + continue; + + for (Set<PlaceHolderScriptInstance *>::Element *P = script->placeholders.front(); P; P = P->next()) { + PlaceHolderScriptInstance *p = P->get(); + script->_update_placeholder(p); + } + } + + } break; + default: { + }; + } +#endif +} + +// Resource loader/saver + RES ResourceFormatLoaderDLScript::load(const String &p_path, const String &p_original_path, Error *r_error) { ResourceFormatLoaderText rsflt; return rsflt.load(p_path, p_original_path, r_error); diff --git a/modules/dlscript/dl_script.h b/modules/dlscript/dl_script.h index e291270fc3..630ce21883 100644 --- a/modules/dlscript/dl_script.h +++ b/modules/dlscript/dl_script.h @@ -34,15 +34,31 @@ #include "io/resource_saver.h" #include "os/thread_safe.h" #include "resource.h" +#include "scene/main/node.h" #include "script_language.h" #include "self_list.h" #include "godot.h" #ifdef TOOLS_ENABLED -// #define DLSCRIPT_EDITOR_FEATURES +#define DLSCRIPT_EDITOR_FEATURES #endif +class DLScriptData; +class DLLibrary; + +struct NativeLibrary { + StringName path; + void *handle; + + DLLibrary *dllib; + + Map<StringName, DLScriptData *> scripts; + + static Error initialize(NativeLibrary *&p_native_lib, const StringName p_path); + static Error terminate(NativeLibrary *&p_native_lib); +}; + struct DLScriptData { /* typedef void* (InstanceFunc)(godot_object* instance); typedef void (DestroyFunc)(godot_object* instance,void* userdata); @@ -118,7 +134,6 @@ struct DLScriptData { class DLLibrary; class DLScript : public Script { - GDCLASS(DLScript, Script); Ref<DLLibrary> library; @@ -129,12 +144,14 @@ class DLScript : public Script { #ifdef TOOLS_ENABLED Set<PlaceHolderScriptInstance *> placeholders; -// void _update_placeholder(PlaceHolderScriptInstance *p_placeholder); -// virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder); + void _update_placeholder(PlaceHolderScriptInstance *p_placeholder); + virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder); #endif friend class DLInstance; friend class DLScriptLanguage; + friend class DLReloadNode; + friend class DLLibrary; protected: static void _bind_methods(); @@ -188,23 +205,13 @@ class DLLibrary : public Resource { OBJ_SAVE_TYPE(DLLibrary); Map<StringName, String> platform_files; - void *library_handle; - String library_path; + NativeLibrary *native_library; static DLLibrary *currently_initialized_library; - Map<StringName, DLScriptData *> scripts; protected: friend class DLScript; - _FORCE_INLINE_ void _update_library(const DLLibrary &p_other) { - platform_files = p_other.platform_files; - library_handle = p_other.library_handle; - library_path = p_other.library_path; - scripts = p_other.scripts; - } - - Error _initialize_handle(bool p_in_editor = false); - - Error _free_handle(bool p_in_editor = false); + friend class NativeLibrary; + friend class DLReloadNode; DLScriptData *get_script_data(const StringName p_name); @@ -215,6 +222,9 @@ protected: static void _bind_methods(); public: + Error _initialize(); + Error _terminate(); + static DLLibrary *get_currently_initialized_library(); void _register_script(const StringName p_name, const StringName p_base, godot_instance_create_func p_instance_func, godot_instance_destroy_func p_destroy_func); @@ -274,9 +284,13 @@ public: ~DLInstance(); }; +class DLReloadNode; + class DLScriptLanguage : public ScriptLanguage { friend class DLScript; friend class DLInstance; + friend class DLReloadNode; + friend class DLLibrary; static DLScriptLanguage *singleton; @@ -289,9 +303,7 @@ class DLScriptLanguage : public ScriptLanguage { Mutex *lock; - SelfList<DLScript>::List script_list; - - Map<String, DLLibrary *> initialized_libraries; + Set<DLScript *> script_list; bool profiling; uint64_t script_frame_time; @@ -303,15 +315,12 @@ class DLScriptLanguage : public ScriptLanguage { } strings; public: + Map<StringName, NativeLibrary *> initialized_libraries; + _FORCE_INLINE_ static DLScriptLanguage *get_singleton() { return singleton; } virtual String get_name() const; - bool is_library_initialized(const String &p_path); - void set_library_initialized(const String &p_path, DLLibrary *p_dllibrary); - DLLibrary *get_library_dllibrary(const String &p_path); - void set_library_uninitialized(const String &p_path); - /* LANGUAGE FUNCTIONS */ virtual void init(); virtual String get_type() const; @@ -386,6 +395,13 @@ public: ~DLScriptLanguage(); }; +class DLReloadNode : public Node { + GDCLASS(DLReloadNode, Node) +public: + static void _bind_methods(); + void _notification(int p_what); +}; + class ResourceFormatLoaderDLScript : public ResourceFormatLoader { public: virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); |