diff options
author | RĂ©mi Verschelde <remi@verschelde.fr> | 2021-02-10 14:31:29 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-10 14:31:29 +0100 |
commit | b1c60c757f55e300b2fccc457f0ea15b095dbec4 (patch) | |
tree | 07e828732de4f93f4431cc37677793bae9a2444a | |
parent | bad2998fea7c5b13688a507de76f8925210a9bf0 (diff) | |
parent | c390c82014c23d7396cec731fceb515a354fe752 (diff) |
Merge pull request #31747 from KoBeWi/scene_stalking
Detect external modification of scenes
-rw-r--r-- | core/config/project_settings.cpp | 7 | ||||
-rw-r--r-- | core/config/project_settings.h | 4 | ||||
-rw-r--r-- | editor/editor_data.cpp | 20 | ||||
-rw-r--r-- | editor/editor_data.h | 3 | ||||
-rw-r--r-- | editor/editor_node.cpp | 107 | ||||
-rw-r--r-- | editor/editor_node.h | 9 |
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); |