From 7788fc4fd2d9c6c5e0dbbd2bd5215b06f1aca304 Mon Sep 17 00:00:00 2001 From: "Silc Lizard (Tokage) Renew" <61938263+TokageItLab@users.noreply.github.com> Date: Thu, 18 Jun 2026 18:00:27 +0900 Subject: [PATCH] Make animation folding access cfg only at save/load project time --- editor/animation/animation_track_editor.cpp | 16 ------ editor/docks/scene_tree_dock.cpp | 59 +++++++++++---------- editor/docks/scene_tree_dock.h | 2 +- editor/settings/editor_folding.cpp | 32 ++++++++--- editor/settings/editor_folding.h | 5 +- scene/resources/animation.h | 7 +++ 6 files changed, 65 insertions(+), 56 deletions(-) diff --git a/editor/animation/animation_track_editor.cpp b/editor/animation/animation_track_editor.cpp index bd0beed8d3..3fb2c21d48 100644 --- a/editor/animation/animation_track_editor.cpp +++ b/editor/animation/animation_track_editor.cpp @@ -3984,16 +3984,6 @@ void AnimationTrackEditGroup::gui_input(const Ref &p_event) { bool current_group_folded = !editor->get_current_animation()->editor_is_group_folded(node_name); editor->get_current_animation()->editor_set_group_folded(node_name, current_group_folded); - if (!editor->get_current_animation()->get_path().is_resource_file()) { - EditorNode::get_editor_folding().save_scene_folding( - EditorNode::get_singleton()->get_edited_scene(), - EditorNode::get_singleton()->get_edited_scene()->get_scene_file_path()); - } else { - EditorNode::get_editor_folding().save_resource_folding( - editor->get_current_animation(), - editor->get_current_animation()->get_path()); - } - for (AnimationTrackEdit *i : track_edits) { i->set_visible(!current_group_folded); } @@ -4141,12 +4131,6 @@ void AnimationTrackEditor::set_animation(const Ref &p_anim, bool p_re } } } - - if (animation->get_path().is_resource_file()) { - EditorNode::get_editor_folding().load_resource_folding( - animation, - animation->get_path()); - } } else { hscroll->hide(); edit->set_disabled(true); diff --git a/editor/docks/scene_tree_dock.cpp b/editor/docks/scene_tree_dock.cpp index f5bff94b0e..e8325c6fe3 100644 --- a/editor/docks/scene_tree_dock.cpp +++ b/editor/docks/scene_tree_dock.cpp @@ -2241,7 +2241,7 @@ bool SceneTreeDock::_check_node_path_recursive(Node *p_root_node, Variant &r_var return false; } -void SceneTreeDock::perform_node_renames(Node *p_base, HashMap *p_renames, HashMap, HashSet> *r_rem_anims) { +void SceneTreeDock::perform_node_renames(Node *p_base, HashMap *p_renames, HashMap, HashSet> *r_rem_anims, LocalVector> *r_folded_group_renames) { HashMap, HashSet> rem_anims; if (!r_rem_anims) { r_rem_anims = &rem_anims; @@ -2263,6 +2263,28 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap bool autorename_animation_tracks = bool(EDITOR_GET("editors/animation/autorename_animation_tracks")); + // key.get_path() of p_renames is like: + // /root/@EditorNode@18033/@Panel@14/.../Scene/TheOldName + // value of p_renames is like: + // /root/@EditorNode@18033/@Panel@14/.../Scene/TheNewName + LocalVector> folded_group_renames; + if (!r_folded_group_renames) { + r_folded_group_renames = &folded_group_renames; + if (autorename_animation_tracks) { + for (const KeyValue &rename : *p_renames) { + if (rename.value.get_name_count() == 0) { + continue; // Node will be deleted (empty path), not renamed. + } + const StringName old_node_name = rename.key->get_name(); + const StringName new_node_name = rename.value.get_name(rename.value.get_name_count() - 1); + if (old_node_name == new_node_name) { + continue; // Only the parent path changed; the name itself didn't. + } + r_folded_group_renames->push_back(Pair(old_node_name, new_node_name)); + } + } + } + AnimationMixer *mixer = Object::cast_to(p_base); if (autorename_animation_tracks && mixer) { // Don't rename if we're an AnimationTree pointing to an AnimationPlayer @@ -2349,33 +2371,14 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap } } - // key.get_path() of p_renames is like: - // /root/@EditorNode@18033/@Panel@14/.../Scene/TheOldName - // value of p_renames is like: - // /root/@EditorNode@18033/@Panel@14/.../Scene/TheNewName - for (const KeyValue &rename : *p_renames) { - NodePath old_path = rename.key->get_path(); - NodePath new_path = rename.value; - if (new_path.is_empty()) { - continue; + // Prevent to rewrite an editable child's inner fold state by parent renaming. + if (p_base == edited_scene || (p_base->get_owner() == edited_scene && p_base->get_scene_file_path().is_empty())) { + for (const Pair &group_rename : *r_folded_group_renames) { + if (anim->editor_is_group_folded(group_rename.first)) { + anim->editor_set_group_folded(group_rename.second, true); + anim->editor_set_group_folded(group_rename.first, false); + } } - Vector rel_path = old_path.rel_path_to(new_path).get_names(); - - StringName old_node_name = rename.key->get_name(); - StringName new_node_name = rel_path[rel_path.size() - 1]; - - anim->editor_set_group_folded(new_node_name, anim->editor_is_group_folded(old_node_name)); - anim->editor_set_group_folded(old_node_name, false); - } - - if (!anim->get_path().is_resource_file()) { - EditorNode::get_editor_folding().save_scene_folding( - EditorNode::get_singleton()->get_edited_scene(), - EditorNode::get_singleton()->get_edited_scene()->get_scene_file_path()); - } else { - EditorNode::get_editor_folding().save_resource_folding( - anim, - anim->get_path()); } } } @@ -2387,7 +2390,7 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap _check_object_properties_recursive(p_base, p_base, p_renames); for (int i = 0; i < p_base->get_child_count(); i++) { - perform_node_renames(p_base->get_child(i), p_renames, r_rem_anims); + perform_node_renames(p_base->get_child(i), p_renames, r_rem_anims, r_folded_group_renames); } } diff --git a/editor/docks/scene_tree_dock.h b/editor/docks/scene_tree_dock.h index 0c0da8dfe7..adc04d153f 100644 --- a/editor/docks/scene_tree_dock.h +++ b/editor/docks/scene_tree_dock.h @@ -337,7 +337,7 @@ public: void set_selection(const Vector &p_nodes); void set_selected(Node *p_node, bool p_emit_selected = false); void fill_path_renames(Node *p_node, Node *p_new_parent, HashMap *p_renames); - void perform_node_renames(Node *p_base, HashMap *p_renames, HashMap, HashSet> *r_rem_anims = nullptr); + void perform_node_renames(Node *p_base, HashMap *p_renames, HashMap, HashSet> *r_rem_anims = nullptr, LocalVector> *r_folded_group_renames = nullptr); void perform_node_replace(Node *p_base, Node *p_node, Node *p_by_node); SceneTreeEditor *get_tree_editor() { return scene_tree; } EditorData *get_editor_data() { return editor_data; } diff --git a/editor/settings/editor_folding.cpp b/editor/settings/editor_folding.cpp index 916d25bc81..de00839ec3 100644 --- a/editor/settings/editor_folding.cpp +++ b/editor/settings/editor_folding.cpp @@ -66,6 +66,11 @@ void EditorFolding::save_resource_folding(const Ref &p_resource, const String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg"; file = EditorPaths::get_singleton()->get_project_settings_dir().path_join(file); config->save(file); + + if (as_anim.is_valid()) { + // Folding state have been stored into the .cfg, clear the dirty flag. + as_anim->editor_set_folding_dirty(false); + } } void EditorFolding::_set_unfolds(Object *p_object, const Vector &p_unfolds) { @@ -102,7 +107,7 @@ void EditorFolding::load_resource_folding(Ref p_resource, const String } } -void EditorFolding::_fill_folds(const Node *p_root, const Node *p_node, Array &p_folds, Array &resource_folds, Array &nodes_folded, HashSet> &resources, HashSet> &animations, Array &anim_groups_folded) { +void EditorFolding::_fill_folds(const Node *p_root, const Node *p_node, Array &p_folds, Array &resource_folds, Array &nodes_folded, HashSet> &resources, HashSet> &animations, Array &anim_groups_folded, HashSet> &r_external_anims) { if (p_root != p_node) { if (!p_node->get_owner()) { return; //not owned, bye @@ -128,10 +133,17 @@ void EditorFolding::_fill_folds(const Node *p_root, const Node *p_node, Array &p anim_mixer->get_animation_list(&anim_names); for (const StringName &anim_name : anim_names) { Ref anim = anim_mixer->get_animation(anim_name); - if (anim.is_valid() && !animations.has(anim) && !anim->get_path().is_empty() && !anim->get_path().is_resource_file()) { - Vector anim_folds = _get_animation_folds(anim.ptr()); - anim_groups_folded.push_back(anim->get_path()); - anim_groups_folded.push_back(anim_folds); + if (anim.is_valid() && !animations.has(anim) && !anim->get_path().is_empty()) { + if (anim->get_path().is_resource_file()) { + // Save .cfg separate from external animation resource. + if (anim->editor_is_folding_dirty()) { + r_external_anims.insert(anim); + } + } else { + Vector anim_folds = _get_animation_folds(anim.ptr()); + anim_groups_folded.push_back(anim->get_path()); + anim_groups_folded.push_back(anim_folds); + } animations.insert(anim); } } @@ -154,7 +166,7 @@ void EditorFolding::_fill_folds(const Node *p_root, const Node *p_node, Array &p } for (int i = 0; i < p_node->get_child_count(); i++) { - _fill_folds(p_root, p_node->get_child(i), p_folds, resource_folds, nodes_folded, resources, animations, anim_groups_folded); + _fill_folds(p_root, p_node->get_child(i), p_folds, resource_folds, nodes_folded, resources, animations, anim_groups_folded, r_external_anims); } } @@ -174,7 +186,8 @@ void EditorFolding::save_scene_folding(const Node *p_scene, const String &p_path Array nodes_folded; HashSet> animations; Array anim_groups_folded; - _fill_folds(p_scene, p_scene, unfolds, res_unfolds, nodes_folded, resources, animations, anim_groups_folded); + HashSet> external_anims; + _fill_folds(p_scene, p_scene, unfolds, res_unfolds, nodes_folded, resources, animations, anim_groups_folded, external_anims); config->set_value("folding", "node_unfolds", unfolds); config->set_value("folding", "resource_unfolds", res_unfolds); @@ -184,6 +197,11 @@ void EditorFolding::save_scene_folding(const Node *p_scene, const String &p_path String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg"; file = EditorPaths::get_singleton()->get_project_settings_dir().path_join(file); config->save(file); + + // Special case for persist folding for external (resource-file) animations referenced by the scene. + for (const Ref &anim : external_anims) { + save_resource_folding(anim, anim->get_path()); + } } void EditorFolding::load_scene_folding(Node *p_scene, const String &p_path) { diff --git a/editor/settings/editor_folding.h b/editor/settings/editor_folding.h index fc0a3cdbf7..3eb8b38d50 100644 --- a/editor/settings/editor_folding.h +++ b/editor/settings/editor_folding.h @@ -38,7 +38,7 @@ class EditorFolding { Vector _get_unfolds(const Object *p_object); void _set_unfolds(Object *p_object, const Vector &p_unfolds); - void _fill_folds(const Node *p_root, const Node *p_node, Array &p_folds, Array &resource_folds, Array &nodes_folded, HashSet> &resources, HashSet> &animations, Array &anim_groups_folded); + void _fill_folds(const Node *p_root, const Node *p_node, Array &p_folds, Array &resource_folds, Array &nodes_folded, HashSet> &resources, HashSet> &animations, Array &anim_groups_folded, HashSet> &r_external_anims); void _do_object_unfolds(Object *p_object, HashSet> &resources); void _do_node_unfolds(Node *p_root, Node *p_node, HashSet> &resources); @@ -53,9 +53,6 @@ public: void save_scene_folding(const Node *p_scene, const String &p_path); void load_scene_folding(Node *p_scene, const String &p_path); - void save_animation_folding(const Ref &p_animation, const String &p_path); - void load_animation_folding(Ref p_animation, const String &p_path); - void unfold_scene(Node *p_scene); bool has_folding_data(const String &p_path); diff --git a/scene/resources/animation.h b/scene/resources/animation.h index 0996704e67..1a6b8016f2 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -259,6 +259,7 @@ private: LocalVector tracks; #ifdef TOOLS_ENABLED HashSet folded_groups; + bool folded_groups_dirty = false; // Set when changing folding state to access .cfg to store the state. #endif // TOOLS_ENABLED template @@ -554,12 +555,18 @@ public: void editor_remove_folded_group(const StringName &p_group_name) { folded_groups.erase(p_group_name); } bool editor_is_group_folded(const StringName &p_group_name) const { return folded_groups.has(p_group_name); } void editor_set_group_folded(const StringName &p_group_name, bool p_folded) { + if (editor_is_group_folded(p_group_name) == p_folded) { + return; // Do nothing. + } if (p_folded) { editor_add_folded_group(p_group_name); } else { editor_remove_folded_group(p_group_name); } + folded_groups_dirty = true; } + bool editor_is_folding_dirty() const { return folded_groups_dirty; } + void editor_set_folding_dirty(bool p_dirty) { folded_groups_dirty = p_dirty; } #endif // TOOLS_ENABLED // Helper functions for Rotation.