summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPedro J. Estébanez <pedrojrulez@gmail.com>2023-06-07 13:44:37 +0200
committerPedro J. Estébanez <pedrojrulez@gmail.com>2023-06-13 11:05:57 +0200
commit96c469a1388a430456465b602ea49bf69ef782c3 (patch)
treeca9d2818e09aa465246dc4a99d737cb64b57216b
parent828ec2c5d005b6499c7c4c88beaf81767d05614b (diff)
downloadredot-engine-96c469a1388a430456465b602ea49bf69ef782c3.tar.gz
Let editor workaround a case of inconsistency in compound scenes
-rw-r--r--doc/classes/EditorInterface.xml6
-rw-r--r--editor/editor_interface.cpp7
-rw-r--r--editor/editor_interface.h1
-rw-r--r--editor/editor_node.cpp12
-rw-r--r--editor/editor_node.h1
-rw-r--r--scene/resources/packed_scene.cpp32
-rw-r--r--scene/resources/packed_scene.h12
7 files changed, 70 insertions, 1 deletions
diff --git a/doc/classes/EditorInterface.xml b/doc/classes/EditorInterface.xml
index 418548a95f..effce40b12 100644
--- a/doc/classes/EditorInterface.xml
+++ b/doc/classes/EditorInterface.xml
@@ -179,6 +179,12 @@
Returns mesh previews rendered at the given size as an [Array] of [Texture2D]s.
</description>
</method>
+ <method name="mark_scene_as_unsaved">
+ <return type="void" />
+ <description>
+ Marks the current scene tab as unsaved.
+ </description>
+ </method>
<method name="open_scene_from_path">
<return type="void" />
<param index="0" name="scene_filepath" type="String" />
diff --git a/editor/editor_interface.cpp b/editor/editor_interface.cpp
index 50833c3a09..d9d9dc01c0 100644
--- a/editor/editor_interface.cpp
+++ b/editor/editor_interface.cpp
@@ -36,6 +36,7 @@
#include "editor/editor_resource_preview.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/filesystem_dock.h"
#include "editor/gui/editor_run_bar.h"
#include "editor/inspector_dock.h"
@@ -332,6 +333,10 @@ void EditorInterface::save_scene_as(const String &p_scene, bool p_with_preview)
EditorNode::get_singleton()->save_scene_to_path(p_scene, p_with_preview);
}
+void EditorInterface::mark_scene_as_unsaved() {
+ EditorUndoRedoManager::get_singleton()->set_history_as_unsaved(EditorNode::get_editor_data().get_current_edited_scene_history_id());
+}
+
// Scene playback.
void EditorInterface::play_main_scene() {
@@ -430,6 +435,8 @@ void EditorInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("save_scene"), &EditorInterface::save_scene);
ClassDB::bind_method(D_METHOD("save_scene_as", "path", "with_preview"), &EditorInterface::save_scene_as, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("mark_scene_as_unsaved"), &EditorInterface::mark_scene_as_unsaved);
+
// Scene playback.
ClassDB::bind_method(D_METHOD("play_main_scene"), &EditorInterface::play_main_scene);
diff --git a/editor/editor_interface.h b/editor/editor_interface.h
index 95fa0dd64f..f7e8cf8d4c 100644
--- a/editor/editor_interface.h
+++ b/editor/editor_interface.h
@@ -129,6 +129,7 @@ public:
Error save_scene();
void save_scene_as(const String &p_scene, bool p_with_preview = true);
+ void mark_scene_as_unsaved();
// Scene playback.
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index bc61661a83..4795fca03d 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -4103,6 +4103,13 @@ void EditorNode::add_io_error(const String &p_error) {
EditorInterface::get_singleton()->popup_dialog_centered_ratio(singleton->load_error_dialog, 0.5);
}
+void EditorNode::add_io_warning(const String &p_warning) {
+ DEV_ASSERT(Thread::get_caller_id() == Thread::get_main_id());
+ singleton->load_errors->add_image(singleton->gui_base->get_theme_icon(SNAME("Warning"), SNAME("EditorIcons")));
+ singleton->load_errors->add_text(p_warning + "\n");
+ EditorInterface::get_singleton()->popup_dialog_centered_ratio(singleton->load_error_dialog, 0.5);
+}
+
bool EditorNode::_find_scene_in_use(Node *p_node, const String &p_path) const {
if (p_node->get_scene_file_path() == p_path) {
return true;
@@ -6806,6 +6813,11 @@ EditorNode::EditorNode() {
ResourceLoader::set_error_notify_func(&EditorNode::add_io_error);
ResourceLoader::set_dependency_error_notify_func(&EditorNode::_dependency_error_report);
+ SceneState::set_instantiation_warning_notify_func([](const String &p_warning) {
+ add_io_warning(p_warning);
+ callable_mp(EditorInterface::get_singleton(), &EditorInterface::mark_scene_as_unsaved).call_deferred();
+ });
+
{
// Register importers at the beginning, so dialogs are created with the right extensions.
Ref<ResourceImporterTexture> import_texture;
diff --git a/editor/editor_node.h b/editor/editor_node.h
index edcad7e4d1..65f85a76c9 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -731,6 +731,7 @@ public:
static bool has_unsaved_changes() { return singleton->unsaved_cache; }
static void disambiguate_filenames(const Vector<String> p_full_paths, Vector<String> &r_filenames);
static void add_io_error(const String &p_error);
+ static void add_io_warning(const String &p_warning);
static void progress_add_task(const String &p_task, const String &p_label, int p_steps, bool p_can_cancel = false);
static bool progress_task_step(const String &p_task, const String &p_state, int p_step = -1, bool p_force_refresh = true);
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index 4d690bd3b1..6708c78177 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -45,6 +45,10 @@
#define PACKED_SCENE_VERSION 3
+#ifdef TOOLS_ENABLED
+SceneState::InstantiationWarningNotify SceneState::instantiation_warn_notify = nullptr;
+#endif
+
bool SceneState::can_instantiate() const {
return nodes.size() > 0;
}
@@ -380,7 +384,33 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
//if node was not part of instance, must set its name, parenthood and ownership
if (i > 0) {
if (parent) {
- parent->_add_child_nocheck(node, snames[n.name]);
+ bool pending_add = true;
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ Node *existing = parent->_get_child_by_name(snames[n.name]);
+ if (existing) {
+ // There's already a node in the same parent with the same name.
+ // This means that somehow the node was added both to the scene being
+ // loaded and another one instantiated in the former, maybe because of
+ // manual editing, or a bug in scene saving, or a loophole in the workflow
+ // (with any of the bugs possibly already fixed).
+ // Bring consistency back by letting it be assigned a non-clashing name.
+ // This simple workaround at least avoids leaks and helps the user realize
+ // something awkward has happened.
+ if (instantiation_warn_notify) {
+ instantiation_warn_notify(vformat(
+ TTR("An incoming node's name clashes with %s already in the scene (presumably, from a more nested instance).\nThe less nested node will be renamed. Please fix and re-save the scene."),
+ ret_nodes[0]->get_path_to(existing)));
+ }
+ node->set_name(snames[n.name]);
+ parent->add_child(node, true);
+ pending_add = false;
+ }
+ }
+#endif
+ if (pending_add) {
+ parent->_add_child_nocheck(node, snames[n.name]);
+ }
if (n.index >= 0 && n.index < parent->get_child_count() - 1) {
parent->move_child(node, n.index);
}
diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h
index 5c53ffdb45..29df382c1f 100644
--- a/scene/resources/packed_scene.h
+++ b/scene/resources/packed_scene.h
@@ -102,6 +102,14 @@ class SceneState : public RefCounted {
int _find_base_scene_node_remap_key(int p_idx) const;
+#ifdef TOOLS_ENABLED
+public:
+ typedef void (*InstantiationWarningNotify)(const String &p_warning);
+
+private:
+ static InstantiationWarningNotify instantiation_warn_notify;
+#endif
+
protected:
static void _bind_methods();
@@ -201,6 +209,10 @@ public:
// Used when saving pointers (saves a path property instead).
static String get_meta_pointer_property(const String &p_property);
+#ifdef TOOLS_ENABLED
+ static void set_instantiation_warning_notify_func(InstantiationWarningNotify p_warn_notify) { instantiation_warn_notify = p_warn_notify; }
+#endif
+
SceneState();
};