diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index 2a7a675f2d0..3037f603c4f 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -1775,9 +1775,9 @@ void ResourceFormatSaverBinaryInstance::write_variant(Ref f, const V case Variant::OBJECT: { f->store_32(VARIANT_OBJECT); Ref res = p_property; - if (res.is_null()) { + if (res.is_null() || res->get_meta(SNAME("_skip_save_"), false)) { f->store_32(OBJECT_EMPTY); - return; // don't save it + return; // Don't save it. } if (!res->is_built_in()) { @@ -1942,7 +1942,7 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant &p_variant case Variant::OBJECT: { Ref res = p_variant; - if (res.is_null() || external_resources.has(res)) { + if (res.is_null() || external_resources.has(res) || res->get_meta(SNAME("_skip_save_"), false)) { return; } diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp index 8e3a247ace3..a17f4977255 100644 --- a/editor/import_dock.cpp +++ b/editor/import_dock.cpp @@ -35,6 +35,7 @@ #include "editor/editor_resource_preview.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" class ImportDockParameters : public Object { GDCLASS(ImportDockParameters, Object); @@ -466,7 +467,6 @@ static bool _find_owners(EditorFileSystemDirectory *efsd, const String &p_path) } void ImportDock::_reimport_attempt() { - bool need_restart = false; bool used_in_resources = false; String importer_name; @@ -483,14 +483,15 @@ void ImportDock::_reimport_attempt() { String imported_with = config->get_value("remap", "importer"); if (imported_with != importer_name) { - need_restart = true; + need_cleanup.push_back(params->paths[i]); if (_find_owners(EditorFileSystem::get_singleton()->get_filesystem(), params->paths[i])) { used_in_resources = true; } } } - if (need_restart) { + if (!need_cleanup.is_empty() || used_in_resources) { + cleanup_warning->set_visible(!need_cleanup.is_empty()); label_warning->set_visible(used_in_resources); reimport_confirm->popup_centered(); return; @@ -499,11 +500,42 @@ void ImportDock::_reimport_attempt() { _reimport(); } -void ImportDock::_reimport_and_restart() { - EditorNode::get_singleton()->save_all_scenes(); - EditorResourcePreview::get_singleton()->stop(); //don't try to re-create previews after import +void ImportDock::_reimport_and_cleanup() { + HashMap> old_resources; + + for (const String &path : need_cleanup) { + Ref res = ResourceLoader::load(path); + res->set_path(""); + res->set_meta(SNAME("_skip_save_"), true); + old_resources[path] = res; + } + + EditorResourcePreview::get_singleton()->stop(); // Don't try to re-create previews after import. _reimport(); - EditorNode::get_singleton()->restart_editor(); + + if (need_cleanup.is_empty()) { + return; + } + + // After changing resource type we need to make sure that all old instances are unloaded or replaced. + EditorNode::get_singleton()->push_item(nullptr); + EditorUndoRedoManager::get_singleton()->clear_history(); + + List> external_resources; + ResourceCache::get_cached_resources(&external_resources); + + for (const String &path : need_cleanup) { + Ref old_res = old_resources[path]; + Ref new_res = ResourceLoader::load(path); + + for (int j = 0; j < EditorNode::get_editor_data().get_edited_scene_count(); j++) { + _replace_resource_in_object(EditorNode::get_editor_data().get_edited_scene_root(j), old_res, new_res); + } + for (Ref res : external_resources) { + _replace_resource_in_object(res.ptr(), old_res, new_res); + } + } + need_cleanup.clear(); } void ImportDock::_advanced_options() { @@ -568,6 +600,37 @@ void ImportDock::_reimport() { _set_dirty(false); } +void ImportDock::_replace_resource_in_object(Object *p_object, const Ref &old_resource, const Ref &new_resource) { + ERR_FAIL_NULL(p_object); + + List props; + p_object->get_property_list(&props); + + for (const PropertyInfo &p : props) { + if (p.type != Variant::OBJECT || p.hint != PROPERTY_HINT_RESOURCE_TYPE) { + continue; + } + + Ref res = p_object->get(p.name); + if (res.is_null()) { + continue; + } + + if (res == old_resource) { + p_object->set(p.name, new_resource); + } else { + _replace_resource_in_object(res.ptr(), old_resource, new_resource); + } + } + + Node *n = Object::cast_to(p_object); + if (n) { + for (int i = 0; i < n->get_child_count(); i++) { + _replace_resource_in_object(n->get_child(i), old_resource, new_resource); + } + } +} + void ImportDock::_notification(int p_what) { switch (p_what) { case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { @@ -683,13 +746,13 @@ ImportDock::ImportDock() { advanced->connect("pressed", callable_mp(this, &ImportDock::_advanced_options)); reimport_confirm = memnew(ConfirmationDialog); - reimport_confirm->set_ok_button_text(TTR("Save Scenes, Re-Import, and Restart")); content->add_child(reimport_confirm); - reimport_confirm->connect("confirmed", callable_mp(this, &ImportDock::_reimport_and_restart)); + reimport_confirm->connect("confirmed", callable_mp(this, &ImportDock::_reimport_and_cleanup)); VBoxContainer *vbc_confirm = memnew(VBoxContainer()); - vbc_confirm->add_child(memnew(Label(TTR("Changing the type of an imported file requires editor restart.")))); - label_warning = memnew(Label(TTR("WARNING: Assets exist that use this resource, they may stop loading properly."))); + cleanup_warning = memnew(Label(TTR("The imported resource is currently loaded. All instances will be replaced and undo history will be cleared."))); + vbc_confirm->add_child(cleanup_warning); + label_warning = memnew(Label(TTR("WARNING: Assets exist that use this resource. They may stop loading properly after changing type."))); vbc_confirm->add_child(label_warning); reimport_confirm->add_child(vbc_confirm); diff --git a/editor/import_dock.h b/editor/import_dock.h index f627cd965d1..07c54f8beba 100644 --- a/editor/import_dock.h +++ b/editor/import_dock.h @@ -54,8 +54,10 @@ class ImportDock : public VBoxContainer { HashMap property_values; ConfirmationDialog *reimport_confirm = nullptr; + Label *cleanup_warning = nullptr; Label *label_warning = nullptr; Button *import = nullptr; + List need_cleanup; Control *advanced_spacer = nullptr; Button *advanced = nullptr; @@ -75,9 +77,11 @@ class ImportDock : public VBoxContainer { void _property_toggled(const StringName &p_prop, bool p_checked); void _set_dirty(bool p_dirty); void _reimport_attempt(); - void _reimport_and_restart(); + void _reimport_and_cleanup(); void _reimport(); + void _replace_resource_in_object(Object *p_object, const Ref &old_resource, const Ref &new_resource); + void _advanced_options(); enum { ITEM_SET_AS_DEFAULT = 100, diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 7719cc28d27..dc0240859e1 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -1828,6 +1828,10 @@ String ResourceFormatSaverTextInstance::_write_resources(void *ud, const Ref &res) { + if (res->get_meta(SNAME("_skip_save_"), false)) { + return "null"; + } + if (external_resources.has(res)) { return "ExtResource(\"" + external_resources[res] + "\")"; } else { @@ -1852,7 +1856,7 @@ void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant, case Variant::OBJECT: { Ref res = p_variant; - if (res.is_null() || external_resources.has(res)) { + if (res.is_null() || external_resources.has(res) || res->get_meta(SNAME("_skip_save_"), false)) { return; }