From ee6c811c9f5ccf289ad44fbc29d496aed8577c0d Mon Sep 17 00:00:00 2001 From: Gustav Lund Date: Sat, 14 Sep 2019 15:25:54 +0200 Subject: [PATCH] Fix for interactive loader with subscenes When polling the interactive loader for an external subscene a temporary interactive loader for the subscene is spawned. Subsequent polls to the main loader will then poll the subscene loader instead of normal behavior until the subscene is completely loaded. A new get_load_step_count() method has been added to the packed_scene class that recursively add together load steps from all of its subscenes load_interactive has been implemented for ResourceFormatImporter load_interactive has been implemented for gd scripts as well The result of this commit is that the interactive loader now loads subscenes in several polls instead of loading the entire subscene in 1 poll. This should result in smoother loading bars and (perhaps more importantly) better background loading --- core/io/resource_format_binary.cpp | 2 +- core/io/resource_importer.cpp | 16 ++- core/io/resource_importer.h | 1 + core/io/resource_loader.cpp | 6 + core/io/resource_loader.h | 3 + modules/gdscript/gdscript.cpp | 134 ++++++++++++++++++++++- modules/gdscript/gdscript.h | 33 +++++- modules/gdscript/gdscript_parser.cpp | 13 ++- modules/gdscript/gdscript_parser.h | 2 + scene/resources/packed_scene.cpp | 110 +++++++++++++++++++ scene/resources/packed_scene.h | 2 + scene/resources/resource_format_text.cpp | 87 +++++++++++++-- scene/resources/resource_format_text.h | 2 + 13 files changed, 394 insertions(+), 17 deletions(-) diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index e91dd579b503..35c2a3ad297e 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -762,7 +762,7 @@ Error ResourceInteractiveLoaderBinary::poll() { error = OK; } - return OK; + return error; } int ResourceInteractiveLoaderBinary::get_stage() const { diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp index 63d7ba547c4c..e1b398e19d35 100644 --- a/core/io/resource_importer.cpp +++ b/core/io/resource_importer.cpp @@ -117,8 +117,22 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy return OK; } -RES ResourceFormatImporter::load(const String &p_path, const String &p_original_path, Error *r_error) { +Ref ResourceFormatImporter::load_interactive(const String &p_path, const String &p_original_path, Error *r_error) { + PathAndType pat; + Error err = _get_path_and_type(p_path, pat); + + if (err != OK) { + + if (r_error) + *r_error = err; + + return RES(); + } + return ResourceLoader::load_interactive(pat.path, pat.type, true, r_error); +} + +RES ResourceFormatImporter::load(const String &p_path, const String &p_original_path, Error *r_error) { PathAndType pat; Error err = _get_path_and_type(p_path, pat); diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h index 9cf298a7f51e..48881f435d2c 100644 --- a/core/io/resource_importer.h +++ b/core/io/resource_importer.h @@ -58,6 +58,7 @@ class ResourceFormatImporter : public ResourceFormatLoader { public: static ResourceFormatImporter *get_singleton() { return singleton; } + virtual Ref 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 void get_recognized_extensions(List *p_extensions) const; virtual void get_recognized_extensions_for_type(const String &p_type, List *p_extensions) const; diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index f3eba449737c..a729139a68c4 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -138,6 +138,12 @@ class ResourceInteractiveLoaderDefault : public ResourceInteractiveLoader { ResourceInteractiveLoaderDefault() {} }; +void ResourceInteractiveLoader::set_preloaded_resources(const Map &p_preloaded_resources) { + for(Map::Element *E=p_preloaded_resources.front();E;E=E->next()) { + preloaded_resources[E->key()] = E->get(); + } +} + Ref ResourceFormatLoader::load_interactive(const String &p_path, const String &p_original_path, Error *r_error) { //either this diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h index 93df8cadb048..c66d2d08f6b4 100644 --- a/core/io/resource_loader.h +++ b/core/io/resource_loader.h @@ -43,6 +43,7 @@ class ResourceInteractiveLoader : public Reference { protected: static void _bind_methods(); + Map preloaded_resources; public: virtual void set_local_path(const String &p_local_path) = 0; @@ -52,6 +53,8 @@ class ResourceInteractiveLoader : public Reference { virtual int get_stage_count() const = 0; virtual void set_translation_remapped(bool p_remapped) = 0; virtual Error wait(); + void set_preloaded_resources(const Map &p_preloaded_resources); + Map get_preloaded_resources(){return preloaded_resources;}; ResourceInteractiveLoader() {} ~ResourceInteractiveLoader(); diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index db7f8d22e6da..6cb1fca5e138 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -540,6 +540,10 @@ void GDScript::_set_subclass_path(Ref &p_sc, const String &p_path) { } Error GDScript::reload(bool p_keep_state) { + return _reload(p_keep_state, Map()); +} + +Error GDScript::_reload(bool p_keep_state, const Map &preloaded_resources) { #ifndef NO_THREADS GDScriptLanguage::singleton->lock->lock(); @@ -567,6 +571,9 @@ Error GDScript::reload(bool p_keep_state) { valid = false; GDScriptParser parser; + +// WARN_PRINT("PARSE"); + parser.set_preloaded_resources(preloaded_resources); Error err = parser.parse(source, basedir, false, path); if (err) { if (ScriptDebugger::get_singleton()) { @@ -578,6 +585,8 @@ Error GDScript::reload(bool p_keep_state) { bool can_run = ScriptServer::is_scripting_enabled() || parser.is_tool_script(); +// WARN_PRINT("COMPILE"); + GDScriptCompiler compiler; err = compiler.compile(&parser, this, p_keep_state); @@ -721,7 +730,7 @@ Vector GDScript::get_as_byte_code() const { return tokenizer.parse_code_string(source); }; -Error GDScript::load_byte_code(const String &p_path) { +Error GDScript::load_byte_code(const String &p_path, const Map &preloaded_resources) { Vector bytecode; @@ -772,6 +781,8 @@ Error GDScript::load_byte_code(const String &p_path) { valid = false; GDScriptParser parser; + WARN_PRINT("PARSE BYTE CODE"); + parser.set_preloaded_resources(preloaded_resources); Error err = parser.parse_bytecode(bytecode, basedir, get_path()); if (err) { _err_print_error("GDScript::load_byte_code", path.empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_error_line(), ("Parse Error: " + parser.get_error()).utf8().get_data(), ERR_HANDLER_SCRIPT); @@ -779,6 +790,7 @@ Error GDScript::load_byte_code(const String &p_path) { } GDScriptCompiler compiler; + WARN_PRINT("COMPILE"); err = compiler.compile(&parser, this); if (err) { @@ -2162,6 +2174,126 @@ GDScriptLanguage::~GDScriptLanguage() { } /*************** RESOURCE ***************/ +void ResourceInteractiveFormatLoaderGDScript::set_local_path(const String &p_local_path) { + +} +Ref ResourceInteractiveFormatLoaderGDScript::get_resource() { + return resource; +} + +Error ResourceInteractiveFormatLoaderGDScript::_poll_dependency() { + error = dependency_loader->poll(); + if (error != ERR_FILE_EOF) { + return error; + } + + RES res = dependency_loader->get_resource(); + set_preloaded_resources(dependency_loader->get_preloaded_resources()); + dependency_loader.unref(); + + preloaded_resources[dependencies[stage]] = res; + + stage++; + return OK; +} + +Error ResourceInteractiveFormatLoaderGDScript::poll() { + if (!dependency_loader.is_null()) { + return _poll_dependency(); + } + + while (stage < dependencies.size()) { + String d = dependencies[stage]; +// WARN_PRINT(String("STAGE: " + itos(stage) + " : " + d).ascii().get_data()); + + if (preloaded_resources.has(d)) { +// WARN_PRINT("Resource already in loaded - skipping"); + stage++; + continue; + } else if (d.ends_with(".gd") || d.ends_with(".tscn") || d.ends_with(".scn")) { + dependency_loader = ResourceLoader::load_interactive(d); + if (dependency_loader.is_null()) { + return ERR_FILE_CORRUPT; + } + dependency_loader->set_preloaded_resources(preloaded_resources); + return _poll_dependency(); + } else { + preloaded_resources[d] = ResourceLoader::load(d); + stage++; + return OK; + } + } + + // Load script itself + + GDScript *script = memnew(GDScript); + Ref scriptres(script); + + if (binary) { + script->set_script_path(original_path); // script needs this. + script->set_path(original_path); + + error = script->load_byte_code(script_path, preloaded_resources); + } else { + error = script->load_source_code(script_path); + + script->set_script_path(original_path); // script needs this. + script->set_path(original_path); + + script->_reload(false, preloaded_resources); + } + + resource = scriptres; + + if (error == OK) { + return ERR_FILE_EOF; + } + return error; +} +int ResourceInteractiveFormatLoaderGDScript::get_stage() const { + return stage; +} +int ResourceInteractiveFormatLoaderGDScript::get_stage_count() const { + return 1; +} + +void ResourceInteractiveFormatLoaderGDScript::set_translation_remapped(bool p_remapped) {} + +ResourceInteractiveFormatLoaderGDScript::ResourceInteractiveFormatLoaderGDScript(){} +ResourceInteractiveFormatLoaderGDScript::~ResourceInteractiveFormatLoaderGDScript(){} + + +Ref ResourceFormatLoaderGDScript::load_interactive(const String &p_path, const String &p_original_path, Error *r_error) { + if (r_error) + *r_error = ERR_CANT_OPEN; + + FileAccessRef file = FileAccess::open(p_path, FileAccess::READ); + if (!file) + *r_error = ERR_CANT_OPEN; + + Ref ria = memnew(ResourceInteractiveFormatLoaderGDScript); + ria->stage = 0; + ria->script_path = p_path; + ria->original_path = p_original_path; + ria->binary = (p_path.ends_with(".gde") || p_path.ends_with(".gdc")); + +// WARN_PRINT("CHECK_DEPENDENCIES"); + String source = file->get_as_utf8_string(); + if (!source.empty()) { + GDScriptParser parser; +// WARN_PRINT("CHECK_SOURCE_OK"); + if (OK == parser.parse(source, p_path.get_base_dir(), true, p_path, false, NULL, true)) { +// WARN_PRINT("OK_PARSE_DEPENDENCIES"); + for (const List::Element *E = parser.get_dependencies().front(); E; E = E->next()) { +// WARN_PRINT(String("DEPENDENCY!: " + E->get()).ascii().get_data()); + String dependency_path = E->get(); + ria->dependencies.push_back(dependency_path); + } + } + } + + return ria; +} RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error) { diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index a5ad23c75ddf..444205e9834c 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -181,10 +181,11 @@ class GDScript : public Script { virtual void update_exports(); virtual Error reload(bool p_keep_state = false); + Error _reload(bool p_keep_state, const Map &preloaded_resources); void set_script_path(const String &p_path) { path = p_path; } //because subclasses need a path too... Error load_source_code(const String &p_path); - Error load_byte_code(const String &p_path); + Error load_byte_code(const String &p_path, const Map &preloaded_resources = Map()); Vector get_as_byte_code() const; @@ -508,8 +509,38 @@ class GDScriptLanguage : public ScriptLanguage { ~GDScriptLanguage(); }; +class ResourceInteractiveFormatLoaderGDScript : public ResourceInteractiveLoader { + friend class ResourceFormatLoaderGDScript; + + int stage; + + String script_path; + String original_path; + bool binary; + + List dependencies; + Ref dependency_loader; + + Error error; + RES resource; + + Error _poll_dependency(); + +public: + virtual void set_local_path(const String &p_local_path); + virtual Ref get_resource(); + virtual Error poll(); + virtual int get_stage() const; + virtual int get_stage_count() const; + virtual void set_translation_remapped(bool p_remapped); + + ResourceInteractiveFormatLoaderGDScript(); + ~ResourceInteractiveFormatLoaderGDScript(); +}; + class ResourceFormatLoaderGDScript : public ResourceFormatLoader { public: + virtual Ref 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 void get_recognized_extensions(List *p_extensions) const; virtual bool handles_type(const String &p_type) const; diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index cf326bef3690..71994f6d2baa 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -487,9 +487,14 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s if (!validating) { //this can be too slow for just validating code - if (for_completion && ScriptCodeCompletionCache::get_singleton() && FileAccess::exists(path)) { + if (preloaded_resources.has(path)) { +// WARN_PRINT(String("GETTING PRELOADED RESOURCE: " + path).ascii().get_data()); + res = preloaded_resources[path]; + } else if (for_completion && ScriptCodeCompletionCache::get_singleton() && FileAccess::exists(path)) { +// WARN_PRINT(String("LOADING CACHED RESOURCE: " + path).ascii().get_data()); res = ScriptCodeCompletionCache::get_singleton()->get_cached_resource(path); } else if (!for_completion || FileAccess::exists(path)) { +// WARN_PRINT(String("LOADING RESOURCE: " + path).ascii().get_data()); res = ResourceLoader::load(path); } } else { @@ -8506,6 +8511,12 @@ Error GDScriptParser::parse(const String &p_code, const String &p_base_path, boo return ret; } +void GDScriptParser::set_preloaded_resources(const Map &p_preloaded_resources) { + for(Map::Element *E=p_preloaded_resources.front();E;E=E->next()) { + preloaded_resources[E->key()] = E->get(); + } +} + bool GDScriptParser::is_tool_script() const { return (head && head->type == Node::TYPE_CLASS && static_cast(head)->tool); diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 04ce9cf4c6d0..dca663030862 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -542,6 +542,7 @@ class GDScriptParser { bool check_types; bool dependencies_only; List dependencies; + Map preloaded_resources; #ifdef DEBUG_ENABLED Set *safe_lines; #endif // DEBUG_ENABLED @@ -665,6 +666,7 @@ class GDScriptParser { int get_completion_identifier_is_function(); const List &get_dependencies() const { return dependencies; } + void set_preloaded_resources(const Map &p_preloaded_resources); void clear(); GDScriptParser(); diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 7d62873bbdb7..908d45328b22 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -1287,6 +1287,116 @@ Dictionary SceneState::get_bundled_scene() const { return d; } +int SceneState::_get_load_step_count(Variant p_variant, Vector *p_found_resources, Vector *p_found_external_resources) const { + int load_step_count = 0; + + switch (p_variant.get_type()) { + case Variant::OBJECT: { + RES res = p_variant.operator RefPtr(); + if (res.is_null()) + return 0; + if (p_found_external_resources->find(res->get_path()) != -1) + return 0; +// WARN_PRINT(String(Variant::get_type_name(p_variant.get_type()) + " - " + res->get_name() + " - " + res->get_path()).ascii().get_data()) +// return 1; + if (p_found_resources->find(res) != -1) + return 0; + +// WARN_PRINT("Get_load_step from OBJECT"); + + if (res->get_path().find("::") != -1) { + // This means that the resource is not external. We should check for sub-resources + List props; + p_variant.get_property_list(&props); + for (List::Element *E = props.front(); E; E = E->next()) { + String name = E->get().name; + Variant value = res->get(name); + + if (!value.is_zero()) { + load_step_count += _get_load_step_count(value, p_found_resources, p_found_external_resources); + } + } + } else { + List props; + p_variant.get_property_list(&props); + bool is_gd_script = false; + for (List::Element *E = props.front(); E; E = E->next()) { + String name = E->get().name; + if (name == "GDScript") { + is_gd_script = true; + } + } + if (is_gd_script) { + List *script_dependencies = memnew(List); + ResourceLoader::get_dependencies(res->get_path(), script_dependencies, false); + load_step_count += script_dependencies->size(); + memdelete(script_dependencies); + } + } + +// WARN_PRINT(String(Variant::get_type_name(p_variant.get_type()) + " - " + res->get_name() + " - " + res->get_path()).ascii().get_data()) +// WARN_PRINT(String("+1 for object: " + res->get_path()).ascii().get_data()); + p_found_resources->push_back(res); + load_step_count++; + } break; + case Variant::ARRAY: { + Array varray = p_variant; + int len = varray.size(); + for (int i = 0; i < len; i++) { + Variant v = varray.get(i); + load_step_count += _get_load_step_count(v, p_found_resources, p_found_external_resources); + } + } break; + case Variant::DICTIONARY: { + Dictionary d = p_variant; + List keys; + d.get_key_list(&keys); + for (List::Element *E = keys.front(); E; E = E->next()) { + Variant v = d[E->get()]; + load_step_count += _get_load_step_count(v, p_found_resources, p_found_external_resources); + } + } break; + default: {} + } + + return load_step_count; +} + +int SceneState::get_load_step_count(Vector *p_found_external_resources) const { + Vector *found_resources = memnew(Vector); + int load_steps = 1; +// WARN_PRINT(String("+1 for scene Start: " + get_path()).ascii().get_data()); + + // Add load steps for objects in subscenes + for (int i = 0; i < get_node_count(); i++) { + //WARN_PRINT(String(get_node_type(i)).ascii().get_data()) + if (is_node_instance_placeholder(i)) + continue; + + Ref instance = get_node_instance(i); + if (instance.is_valid()){ + if (p_found_external_resources->find(instance->get_path()) == -1) { + p_found_external_resources->push_back(instance->get_path()); + load_steps += instance->get_state()->get_load_step_count(p_found_external_resources); + } else { + // Getting an already loaded scene takes a load steps + load_steps += 1; + } + } + } + + // Add load steps for each remaining object in the scene +// WARN_PRINT(String("Checking variants. size of array: " + itos(variants.size())).ascii().get_data()); + for (int i = 0; i < variants.size(); i++) { + load_steps += _get_load_step_count(variants[i], found_resources, p_found_external_resources); +// WARN_PRINT(String("Add from variant... sum: " + itos(load_steps)).ascii().get_data()); + } + + memdelete(found_resources); + + return load_steps; +} + int SceneState::get_node_count() const { return nodes.size(); diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h index 3c05929deae8..7aaf4b07df9f 100644 --- a/scene/resources/packed_scene.h +++ b/scene/resources/packed_scene.h @@ -94,6 +94,7 @@ class SceneState : public Reference { Error _parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map &name_map, HashMap &variant_map, Map &node_map, Map &nodepath_map); Error _parse_connections(Node *p_owner, Node *p_node, Map &name_map, HashMap &variant_map, Map &node_map, Map &nodepath_map); + int _get_load_step_count(Variant p_variant, Vector *p_found_resources, Vector *p_found_external_resources) const; String path; @@ -144,6 +145,7 @@ class SceneState : public Reference { bool can_instance() const; Node *instance(GenEditState p_edit_state) const; + int get_load_step_count(Vector *p_found_external_resources) const; //unbuild API int get_node_count() const; diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index baffc1396d07..5e2c25c646af 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -389,11 +389,50 @@ Ref ResourceInteractiveLoaderText::_parse_node_tag(VariantParser::R return packed_scene; } +Error ResourceInteractiveLoaderText::_poll_subresource() { + error = subscene_loader->poll(); + if (error != ERR_FILE_EOF) { + resource_current++; + return error; + } + + RES res = subscene_loader->get_resource(); + set_preloaded_resources(subscene_loader->get_preloaded_resources()); + subscene_loader.unref(); + + resource_cache.push_back(res); + + String path = next_tag.fields["path"]; + String type = next_tag.fields["type"]; + int index = next_tag.fields["id"]; + + preloaded_resources[path] = res; + + ExtResource er; + er.path = path; + er.type = type; + ext_resources[index] = er; +// WARN_PRINT(String("Loading ext scene ended: " + er.path).ascii().get_data()); + + error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp); + + if (error) { + _printerr(); + } + + resource_current++; + return error; +} + Error ResourceInteractiveLoaderText::poll() { if (error != OK) return error; + if (!subscene_loader.is_null()) { + return _poll_subresource(); + } + if (next_tag.name == "ext_resource") { if (!next_tag.fields.has("path")) { @@ -420,6 +459,7 @@ Error ResourceInteractiveLoaderText::poll() { String path = next_tag.fields["path"]; String type = next_tag.fields["type"]; int index = next_tag.fields["id"]; +// WARN_PRINT(String("Loading ext: " + path + " - " + type).ascii().get_data()); if (path.find("://") == -1 && path.is_rel_path()) { // path is relative to file being loaded, so convert to a resource path @@ -430,6 +470,18 @@ Error ResourceInteractiveLoaderText::poll() { path = remaps[path]; } + if (type == "PackedScene" || type == "Script") { + subscene_loader = ResourceLoader::load_interactive(path); + if (subscene_loader.is_null()) { + error = ERR_FILE_CORRUPT; + error_text = "[ext_resource] referenced nonexistent resource at: " + path; + _printerr(); + return error; + } + subscene_loader->set_preloaded_resources(preloaded_resources); + return _poll_subresource(); + } + RES res = ResourceLoader::load(path, type); if (res.is_null()) { @@ -444,6 +496,7 @@ Error ResourceInteractiveLoaderText::poll() { } } else { + preloaded_resources[path] = res; resource_cache.push_back(res); #ifdef TOOLS_ENABLED //remember ID for saving @@ -485,6 +538,7 @@ Error ResourceInteractiveLoaderText::poll() { int id = next_tag.fields["id"]; String path = local_path + "::" + itos(id); +// WARN_PRINT(String("Loading internal: " + path).ascii().get_data()); //bool exists=ResourceCache::has(path); @@ -1316,6 +1370,17 @@ Error ResourceFormatLoaderText::rename_dependencies(const String &p_path, const ResourceFormatLoaderText *ResourceFormatLoaderText::singleton = NULL; +/*****************************************************************************************************/ +/*****************************************************************************************************/ +/*****************************************************************************************************/ +/*****************************************************************************************************/ +/*****************************************************************************************************/ +/*****************************************************************************************************/ +/*****************************************************************************************************/ +/*****************************************************************************************************/ +/*****************************************************************************************************/ +/*****************************************************************************************************/ + Error ResourceFormatLoaderText::convert_file_to_binary(const String &p_src_path, const String &p_dst_path) { Error err; @@ -1332,17 +1397,6 @@ Error ResourceFormatLoaderText::convert_file_to_binary(const String &p_src_path, return ria->save_as_binary(f, p_dst_path); } -/*****************************************************************************************************/ -/*****************************************************************************************************/ -/*****************************************************************************************************/ -/*****************************************************************************************************/ -/*****************************************************************************************************/ -/*****************************************************************************************************/ -/*****************************************************************************************************/ -/*****************************************************************************************************/ -/*****************************************************************************************************/ -/*****************************************************************************************************/ - String ResourceFormatSaverTextInstance::_write_resources(void *ud, const RES &p_resource) { ResourceFormatSaverTextInstance *rsi = (ResourceFormatSaverTextInstance *)ud; @@ -1513,9 +1567,18 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r { String title = packed_scene.is_valid() ? "[gd_scene " : "[gd_resource "; + if (packed_scene.is_null()) title += "type=\"" + p_resource->get_class() + "\" "; - int load_steps = saved_resources.size() + external_resources.size(); + + int load_steps = 0; + if (packed_scene.is_valid()) { + Vector *found_external_resources = memnew(Vector); + load_steps = packed_scene->get_state()->get_load_step_count(found_external_resources); + memdelete(found_external_resources); + } else { + load_steps = saved_resources.size() + external_resources.size(); + } /* if (packed_scene.is_valid()) { load_steps+=packed_scene->get_node_count(); diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h index 0041989f09b5..af707f2e44bf 100644 --- a/scene/resources/resource_format_text.h +++ b/scene/resources/resource_format_text.h @@ -43,6 +43,7 @@ class ResourceInteractiveLoaderText : public ResourceInteractiveLoader { String local_path; String res_path; String error_text; + Ref subscene_loader; FileAccess *f; @@ -108,6 +109,7 @@ class ResourceInteractiveLoaderText : public ResourceInteractiveLoader { RES resource; Ref _parse_node_tag(VariantParser::ResourceParser &parser); + Error _poll_subresource(); public: virtual void set_local_path(const String &p_local_path);