From bb4c4872754e2a39fca54c0b70f58e5f3765e552 Mon Sep 17 00:00:00 2001 From: Arsh Panesar Date: Mon, 29 Jul 2024 15:16:30 +0530 Subject: [PATCH] Fix `AnimationPlayer` crash when it's made the scene root When an AnimationPlayer is made root of a scene, the track links may become broken and clicking on them will crash. Current master branch also breaks node links when AnimationPlayer is made scene root, and can also crash the engine if another node was made scene root prior to the AnimationPlayer. This happens because when made root, the editor loses track of AnimPlayer's root node. By keeping a copy of the AnimPlayer's root_node, the track links remain functional. Fixes #91043. --- .../plugins/animation_player_editor_plugin.cpp | 16 +++++++++++++++- editor/plugins/animation_player_editor_plugin.h | 2 ++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index b88211295048..5cb558abbeeb 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -402,7 +402,17 @@ void AnimationPlayerEditor::_animation_selected(int p_which) { track_editor->set_animation(anim, animation_is_readonly); Node *root = player->get_node_or_null(player->get_root_node()); - if (root) { + + // Player shouldn't access parent if it's the scene root. + if (!root || (player == get_tree()->get_edited_scene_root() && player->get_root_node() == SceneStringName(path_pp))) { + NodePath cached_root_path = player->get_path_to(get_cached_root_node()); + if (player->get_node_or_null(cached_root_path) != nullptr) { + player->set_root_node(cached_root_path); + } else { + player->set_root_node(SceneStringName(path_pp)); // No other choice, preventing crash. + } + } else { + cached_root_node_id = root->get_instance_id(); // Caching as `track_editor` can lose track of player's root node. track_editor->set_root(root); } } @@ -1886,6 +1896,10 @@ AnimationMixer *AnimationPlayerEditor::fetch_mixer_for_library() const { return original_node; } +Node *AnimationPlayerEditor::get_cached_root_node() const { + return Object::cast_to(ObjectDB::get_instance(cached_root_node_id)); +} + bool AnimationPlayerEditor::_validate_tracks(const Ref p_anim) { bool is_valid = true; if (!p_anim.is_valid()) { diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h index 860d421b91c8..e4ca6c17c39a 100644 --- a/editor/plugins/animation_player_editor_plugin.h +++ b/editor/plugins/animation_player_editor_plugin.h @@ -52,6 +52,7 @@ class AnimationPlayerEditor : public VBoxContainer { AnimationPlayerEditorPlugin *plugin = nullptr; AnimationMixer *original_node = nullptr; // For pinned mark in SceneTree. AnimationPlayer *player = nullptr; // For AnimationPlayerEditor, could be dummy. + ObjectID cached_root_node_id; bool is_dummy = false; enum { @@ -253,6 +254,7 @@ class AnimationPlayerEditor : public VBoxContainer { AnimationMixer *get_editing_node() const; AnimationPlayer *get_player() const; AnimationMixer *fetch_mixer_for_library() const; + Node *get_cached_root_node() const; static AnimationPlayerEditor *get_singleton() { return singleton; }