summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRĂ©mi Verschelde <remi@verschelde.fr>2021-02-10 14:31:29 +0100
committerGitHub <noreply@github.com>2021-02-10 14:31:29 +0100
commitb1c60c757f55e300b2fccc457f0ea15b095dbec4 (patch)
tree07e828732de4f93f4431cc37677793bae9a2444a
parentbad2998fea7c5b13688a507de76f8925210a9bf0 (diff)
parentc390c82014c23d7396cec731fceb515a354fe752 (diff)
Merge pull request #31747 from KoBeWi/scene_stalking
Detect external modification of scenes
-rw-r--r--core/config/project_settings.cpp7
-rw-r--r--core/config/project_settings.h4
-rw-r--r--editor/editor_data.cpp20
-rw-r--r--editor/editor_data.h3
-rw-r--r--editor/editor_node.cpp107
-rw-r--r--editor/editor_node.h9
6 files changed, 145 insertions, 5 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 70e8133eaa..9b28ef7b81 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -597,6 +597,7 @@ Error ProjectSettings::_load_settings_text(const String &p_path) {
// If we're loading a project.godot from source code, we can operate some
// ProjectSettings conversions if need be.
_convert_to_last_version(config_version);
+ last_save_time = FileAccess::get_modified_time(get_resource_path().plus_file("project.godot"));
return OK;
} else if (err != OK) {
ERR_PRINT("Error parsing " + p_path + " at line " + itos(lines) + ": " + error_text + " File might be corrupted.");
@@ -676,7 +677,11 @@ void ProjectSettings::clear(const String &p_name) {
}
Error ProjectSettings::save() {
- return save_custom(get_resource_path().plus_file("project.godot"));
+ Error error = save_custom(get_resource_path().plus_file("project.godot"));
+ if (error == OK) {
+ last_save_time = FileAccess::get_modified_time(get_resource_path().plus_file("project.godot"));
+ }
+ return error;
}
Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<String, List<String>> &props, const CustomMap &p_custom, const String &p_custom_features) {
diff --git a/core/config/project_settings.h b/core/config/project_settings.h
index 59c56c23c2..645506f302 100644
--- a/core/config/project_settings.h
+++ b/core/config/project_settings.h
@@ -78,6 +78,8 @@ protected:
int last_order = NO_BUILTIN_ORDER_BASE;
int last_builtin_order = 0;
+ uint64_t last_save_time = 0;
+
Map<StringName, VariantContainer> props;
String resource_path;
Map<StringName, PropertyInfo> custom_prop_info;
@@ -113,7 +115,6 @@ protected:
Error _setup(const String &p_path, const String &p_main_pack, bool p_upwards = false);
-protected:
static void _bind_methods();
public:
@@ -150,6 +151,7 @@ public:
Error save();
void set_custom_property_info(const String &p_prop, const PropertyInfo &p_info);
const Map<StringName, PropertyInfo> &get_custom_property_info() const;
+ uint64_t get_last_saved_time() { return last_save_time; }
Vector<String> get_optimizer_presets() const;
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index 336bf26607..18364dc32f 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -500,6 +500,7 @@ int EditorData::add_edited_scene(int p_at_pos) {
EditedScene es;
es.root = nullptr;
es.path = String();
+ es.file_modified_time = 0;
es.history_current = -1;
es.version = 0;
es.live_edit_root = NodePath(String("/root"));
@@ -656,6 +657,10 @@ void EditorData::set_edited_scene_root(Node *p_root) {
p_root->set_filename(edited_scene[current_edited_scene].path);
}
}
+
+ if (edited_scene[current_edited_scene].path != "") {
+ edited_scene.write[current_edited_scene].file_modified_time = FileAccess::get_modified_time(edited_scene[current_edited_scene].path);
+ }
}
int EditorData::get_edited_scene_count() const {
@@ -687,6 +692,21 @@ uint64_t EditorData::get_scene_version(int p_idx) const {
return edited_scene[p_idx].version;
}
+void EditorData::set_scene_modified_time(int p_idx, uint64_t p_time) {
+ if (p_idx == -1) {
+ p_idx = current_edited_scene;
+ }
+
+ ERR_FAIL_INDEX(p_idx, edited_scene.size());
+
+ edited_scene.write[p_idx].file_modified_time = p_time;
+}
+
+uint64_t EditorData::get_scene_modified_time(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx, edited_scene.size(), 0);
+ return edited_scene[p_idx].file_modified_time;
+}
+
String EditorData::get_scene_type(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, edited_scene.size(), String());
if (!edited_scene[p_idx].root) {
diff --git a/editor/editor_data.h b/editor/editor_data.h
index f14a3fb4e0..18b4137162 100644
--- a/editor/editor_data.h
+++ b/editor/editor_data.h
@@ -111,6 +111,7 @@ public:
struct EditedScene {
Node *root = nullptr;
String path;
+ uint64_t file_modified_time = 0;
Dictionary editor_states;
List<Node *> selection;
Vector<EditorHistory::History> history_stored;
@@ -190,6 +191,8 @@ public:
Ref<Script> get_scene_root_script(int p_idx) const;
void set_edited_scene_version(uint64_t version, int p_scene_idx = -1);
uint64_t get_scene_version(int p_idx) const;
+ void set_scene_modified_time(int p_idx, uint64_t p_time);
+ uint64_t get_scene_modified_time(int p_idx) const;
void clear_edited_scenes();
void set_edited_scene_live_edit_root(const NodePath &p_root);
NodePath get_edited_scene_live_edit_root();
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 12d0d1db08..8b123bf408 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -594,6 +594,7 @@ void EditorNode::_notification(int p_what) {
OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(int(EDITOR_GET("interface/editor/low_processor_mode_sleep_usec")));
EditorFileSystem::get_singleton()->scan_changes();
+ _scan_external_changes();
} break;
case NOTIFICATION_APPLICATION_FOCUS_OUT: {
@@ -886,6 +887,81 @@ void EditorNode::_sources_changed(bool p_exist) {
}
}
+void EditorNode::_scan_external_changes() {
+ disk_changed_list->clear();
+ TreeItem *r = disk_changed_list->create_item();
+ disk_changed_list->set_hide_root(true);
+ bool need_reload = false;
+
+ // Check if any edited scene has changed.
+
+ for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
+ if (editor_data.get_scene_path(i) == "") {
+ continue;
+ }
+
+ uint64_t last_date = editor_data.get_scene_modified_time(i);
+ uint64_t date = FileAccess::get_modified_time(editor_data.get_scene_path(i));
+
+ if (date > last_date) {
+ TreeItem *ti = disk_changed_list->create_item(r);
+ ti->set_text(0, editor_data.get_scene_path(i).get_file());
+ need_reload = true;
+ }
+ }
+
+ String project_settings_path = ProjectSettings::get_singleton()->get_resource_path().plus_file("project.godot");
+ if (FileAccess::get_modified_time(project_settings_path) > ProjectSettings::get_singleton()->get_last_saved_time()) {
+ TreeItem *ti = disk_changed_list->create_item(r);
+ ti->set_text(0, "project.godot");
+ need_reload = true;
+ }
+
+ if (need_reload) {
+ disk_changed->call_deferred("popup_centered_ratio", 0.5);
+ }
+}
+
+void EditorNode::_resave_scenes(String p_str) {
+ save_all_scenes();
+ ProjectSettings::get_singleton()->save();
+ disk_changed->hide();
+}
+
+void EditorNode::_reload_modified_scenes() {
+ int current_idx = editor_data.get_edited_scene();
+
+ for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
+ if (editor_data.get_scene_path(i) == "") {
+ continue;
+ }
+
+ uint64_t last_date = editor_data.get_scene_modified_time(i);
+ uint64_t date = FileAccess::get_modified_time(editor_data.get_scene_path(i));
+
+ if (date > last_date) {
+ String filename = editor_data.get_scene_path(i);
+ editor_data.set_edited_scene(i);
+ _remove_edited_scene(false);
+
+ Error err = load_scene(filename, false, false, true, false, true);
+ if (err != OK) {
+ ERR_PRINT(vformat("Failed to load scene: %s", filename));
+ }
+ editor_data.move_edited_scene_to_index(i);
+ }
+ }
+
+ get_undo_redo()->clear_history(false);
+ set_current_scene(current_idx);
+ _update_scene_tabs();
+ disk_changed->hide();
+}
+
+void EditorNode::_reload_project_settings() {
+ ProjectSettings::get_singleton()->setup(ProjectSettings::get_singleton()->get_resource_path(), String(), true);
+}
+
void EditorNode::_vp_resized() {
}
@@ -1511,6 +1587,7 @@ void EditorNode::_save_scene(String p_file, int idx) {
} else {
editor_data.set_edited_scene_version(0, idx);
}
+ editor_data.set_scene_modified_time(idx, FileAccess::get_modified_time(p_file));
editor_folding.save_scene_folding(scene, p_file);
@@ -3326,7 +3403,7 @@ int EditorNode::new_scene() {
return idx;
}
-Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, bool p_set_inherited, bool p_clear_errors, bool p_force_open_imported) {
+Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, bool p_set_inherited, bool p_clear_errors, bool p_force_open_imported, bool p_silent_change_tab) {
if (!is_inside_tree()) {
defer_load_scene = p_scene;
return OK;
@@ -3366,8 +3443,10 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b
if (!editor_data.get_edited_scene_root() && editor_data.get_edited_scene_count() == 2) {
_remove_edited_scene();
- } else {
+ } else if (!p_silent_change_tab) {
_scene_tab_changed(idx);
+ } else {
+ set_current_scene(idx);
}
dependency_errors.clear();
@@ -6601,6 +6680,30 @@ EditorNode::EditorNode() {
//plugin stuff
add_editor_plugin(memnew(DebuggerEditorPlugin(this, debug_menu)));
+
+ disk_changed = memnew(ConfirmationDialog);
+ {
+ VBoxContainer *vbc = memnew(VBoxContainer);
+ disk_changed->add_child(vbc);
+
+ Label *dl = memnew(Label);
+ dl->set_text(TTR("The following files are newer on disk.\nWhat action should be taken?"));
+ vbc->add_child(dl);
+
+ disk_changed_list = memnew(Tree);
+ vbc->add_child(disk_changed_list);
+ disk_changed_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+
+ disk_changed->connect("confirmed", callable_mp(this, &EditorNode::_reload_modified_scenes));
+ disk_changed->connect("confirmed", callable_mp(this, &EditorNode::_reload_project_settings));
+ disk_changed->get_ok_button()->set_text(TTR("Reload"));
+
+ disk_changed->add_button(TTR("Resave"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "resave");
+ disk_changed->connect("custom_action", callable_mp(this, &EditorNode::_resave_scenes));
+ }
+
+ gui_base->add_child(disk_changed);
+
add_editor_plugin(memnew(AnimationPlayerEditorPlugin(this)));
add_editor_plugin(memnew(CanvasItemEditorPlugin(this)));
add_editor_plugin(memnew(Node3DEditorPlugin(this)));
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 356ac0caac..3785d29c41 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -422,6 +422,9 @@ private:
Label *version_label;
Button *bottom_panel_raise;
+ Tree *disk_changed_list;
+ ConfirmationDialog *disk_changed;
+
void _bottom_panel_raise_toggled(bool);
EditorInterface *editor_interface;
@@ -641,6 +644,10 @@ private:
static void _resource_loaded(RES p_resource, const String &p_path);
void _resources_changed(const Vector<String> &p_resources);
+ void _scan_external_changes();
+ void _reload_modified_scenes();
+ void _reload_project_settings();
+ void _resave_scenes(String p_str);
void _feature_profile_changed();
bool _is_class_editor_disabled_by_feature_profile(const StringName &p_class);
@@ -741,7 +748,7 @@ public:
void fix_dependencies(const String &p_for_file);
void clear_scene() { _cleanup_scene(); }
int new_scene();
- Error load_scene(const String &p_scene, bool p_ignore_broken_deps = false, bool p_set_inherited = false, bool p_clear_errors = true, bool p_force_open_imported = false);
+ Error load_scene(const String &p_scene, bool p_ignore_broken_deps = false, bool p_set_inherited = false, bool p_clear_errors = true, bool p_force_open_imported = false, bool p_silent_change_tab = false);
Error load_resource(const String &p_resource, bool p_ignore_broken_deps = false);
bool is_scene_open(const String &p_path);