1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-07 12:30:27 +00:00

Allow change import type without restarting editor

This commit is contained in:
kobewi
2023-07-01 01:29:46 +02:00
parent 46424488ed
commit 244968c8d1
4 changed files with 87 additions and 16 deletions

View File

@@ -1775,9 +1775,9 @@ void ResourceFormatSaverBinaryInstance::write_variant(Ref<FileAccess> f, const V
case Variant::OBJECT: { case Variant::OBJECT: {
f->store_32(VARIANT_OBJECT); f->store_32(VARIANT_OBJECT);
Ref<Resource> res = p_property; Ref<Resource> res = p_property;
if (res.is_null()) { if (res.is_null() || res->get_meta(SNAME("_skip_save_"), false)) {
f->store_32(OBJECT_EMPTY); f->store_32(OBJECT_EMPTY);
return; // don't save it return; // Don't save it.
} }
if (!res->is_built_in()) { if (!res->is_built_in()) {
@@ -1942,7 +1942,7 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant &p_variant
case Variant::OBJECT: { case Variant::OBJECT: {
Ref<Resource> res = p_variant; Ref<Resource> 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; return;
} }

View File

@@ -35,6 +35,7 @@
#include "editor/editor_resource_preview.h" #include "editor/editor_resource_preview.h"
#include "editor/editor_scale.h" #include "editor/editor_scale.h"
#include "editor/editor_settings.h" #include "editor/editor_settings.h"
#include "editor/editor_undo_redo_manager.h"
class ImportDockParameters : public Object { class ImportDockParameters : public Object {
GDCLASS(ImportDockParameters, Object); GDCLASS(ImportDockParameters, Object);
@@ -459,7 +460,6 @@ static bool _find_owners(EditorFileSystemDirectory *efsd, const String &p_path)
} }
void ImportDock::_reimport_attempt() { void ImportDock::_reimport_attempt() {
bool need_restart = false;
bool used_in_resources = false; bool used_in_resources = false;
String importer_name; String importer_name;
@@ -476,14 +476,15 @@ void ImportDock::_reimport_attempt() {
String imported_with = config->get_value("remap", "importer"); String imported_with = config->get_value("remap", "importer");
if (imported_with != importer_name) { 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])) { if (_find_owners(EditorFileSystem::get_singleton()->get_filesystem(), params->paths[i])) {
used_in_resources = true; 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); label_warning->set_visible(used_in_resources);
reimport_confirm->popup_centered(); reimport_confirm->popup_centered();
return; return;
@@ -492,11 +493,42 @@ void ImportDock::_reimport_attempt() {
_reimport(); _reimport();
} }
void ImportDock::_reimport_and_restart() { void ImportDock::_reimport_and_cleanup() {
EditorNode::get_singleton()->save_all_scenes(); HashMap<String, Ref<Resource>> old_resources;
EditorResourcePreview::get_singleton()->stop(); //don't try to re-create previews after import
for (const String &path : need_cleanup) {
Ref<Resource> 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(); _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<Ref<Resource>> external_resources;
ResourceCache::get_cached_resources(&external_resources);
for (const String &path : need_cleanup) {
Ref<Resource> old_res = old_resources[path];
Ref<Resource> 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<Resource> res : external_resources) {
_replace_resource_in_object(res.ptr(), old_res, new_res);
}
}
need_cleanup.clear();
} }
void ImportDock::_advanced_options() { void ImportDock::_advanced_options() {
@@ -561,6 +593,37 @@ void ImportDock::_reimport() {
_set_dirty(false); _set_dirty(false);
} }
void ImportDock::_replace_resource_in_object(Object *p_object, const Ref<Resource> &old_resource, const Ref<Resource> &new_resource) {
ERR_FAIL_NULL(p_object);
List<PropertyInfo> 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<Resource> 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<Node>(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) { void ImportDock::_notification(int p_what) {
switch (p_what) { switch (p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
@@ -673,13 +736,13 @@ ImportDock::ImportDock() {
advanced->connect("pressed", callable_mp(this, &ImportDock::_advanced_options)); advanced->connect("pressed", callable_mp(this, &ImportDock::_advanced_options));
reimport_confirm = memnew(ConfirmationDialog); reimport_confirm = memnew(ConfirmationDialog);
reimport_confirm->set_ok_button_text(TTR("Save Scenes, Re-Import, and Restart"));
content->add_child(reimport_confirm); 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()); VBoxContainer *vbc_confirm = memnew(VBoxContainer());
vbc_confirm->add_child(memnew(Label(TTR("Changing the type of an imported file requires editor restart.")))); cleanup_warning = memnew(Label(TTR("The imported resource is currently loaded. All instances will be replaced and undo history will be cleared.")));
label_warning = memnew(Label(TTR("WARNING: Assets exist that use this resource, they may stop loading properly."))); 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); vbc_confirm->add_child(label_warning);
reimport_confirm->add_child(vbc_confirm); reimport_confirm->add_child(vbc_confirm);

View File

@@ -54,8 +54,10 @@ class ImportDock : public VBoxContainer {
HashMap<StringName, Variant> property_values; HashMap<StringName, Variant> property_values;
ConfirmationDialog *reimport_confirm = nullptr; ConfirmationDialog *reimport_confirm = nullptr;
Label *cleanup_warning = nullptr;
Label *label_warning = nullptr; Label *label_warning = nullptr;
Button *import = nullptr; Button *import = nullptr;
List<String> need_cleanup;
Control *advanced_spacer = nullptr; Control *advanced_spacer = nullptr;
Button *advanced = nullptr; Button *advanced = nullptr;
@@ -75,9 +77,11 @@ class ImportDock : public VBoxContainer {
void _property_toggled(const StringName &p_prop, bool p_checked); void _property_toggled(const StringName &p_prop, bool p_checked);
void _set_dirty(bool p_dirty); void _set_dirty(bool p_dirty);
void _reimport_attempt(); void _reimport_attempt();
void _reimport_and_restart(); void _reimport_and_cleanup();
void _reimport(); void _reimport();
void _replace_resource_in_object(Object *p_object, const Ref<Resource> &old_resource, const Ref<Resource> &new_resource);
void _advanced_options(); void _advanced_options();
enum { enum {
ITEM_SET_AS_DEFAULT = 100, ITEM_SET_AS_DEFAULT = 100,

View File

@@ -1828,6 +1828,10 @@ String ResourceFormatSaverTextInstance::_write_resources(void *ud, const Ref<Res
} }
String ResourceFormatSaverTextInstance::_write_resource(const Ref<Resource> &res) { String ResourceFormatSaverTextInstance::_write_resource(const Ref<Resource> &res) {
if (res->get_meta(SNAME("_skip_save_"), false)) {
return "null";
}
if (external_resources.has(res)) { if (external_resources.has(res)) {
return "ExtResource(\"" + external_resources[res] + "\")"; return "ExtResource(\"" + external_resources[res] + "\")";
} else { } else {
@@ -1852,7 +1856,7 @@ void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant,
case Variant::OBJECT: { case Variant::OBJECT: {
Ref<Resource> res = p_variant; Ref<Resource> 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; return;
} }