From 1b95827d3ef244de322b0c16deb49fefe48ed1a1 Mon Sep 17 00:00:00 2001 From: "Silc Lizard (Tokage) Renew" <61938263+TokageItLab@users.noreply.github.com> Date: Fri, 21 Jul 2023 00:34:06 +0900 Subject: Implement AnimationManager the base class of AnimationPlayer/Tree --- editor/animation_track_editor.cpp | 53 +++- editor/animation_track_editor.h | 8 + editor/editor_node.cpp | 25 +- editor/gui/scene_tree_editor.cpp | 6 +- editor/icons/AnimationMixer.svg | 1 + .../import/post_import_plugin_skeleton_renamer.cpp | 6 +- .../post_import_plugin_skeleton_rest_fixer.cpp | 10 +- ...post_import_plugin_skeleton_track_organizer.cpp | 2 +- editor/import/resource_importer_scene.cpp | 2 +- editor/plugins/animation_blend_space_1d_editor.cpp | 16 +- editor/plugins/animation_blend_space_2d_editor.cpp | 15 +- .../plugins/animation_blend_tree_editor_plugin.cpp | 70 ++--- editor/plugins/animation_library_editor.cpp | 124 ++++---- editor/plugins/animation_library_editor.h | 8 +- editor/plugins/animation_player_editor_plugin.cpp | 349 ++++++++++++++++----- editor/plugins/animation_player_editor_plugin.h | 26 +- editor/plugins/animation_state_machine_editor.cpp | 10 +- editor/plugins/animation_tree_editor_plugin.cpp | 24 +- editor/plugins/root_motion_editor_plugin.cpp | 28 +- editor/scene_tree_dock.cpp | 4 +- 20 files changed, 502 insertions(+), 285 deletions(-) create mode 100644 editor/icons/AnimationMixer.svg (limited to 'editor') diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 4f6e7c4b91..7105ff280a 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -2695,7 +2695,7 @@ void AnimationTrackEdit::gui_input(const Ref &p_event) { AnimationPlayer *ap = ape->get_player(); if (ap) { NodePath npath = animation->track_get_path(track); - Node *nd = ap->get_node(ap->get_root())->get_node(NodePath(npath.get_concatenated_names())); + Node *nd = ap->get_node(ap->get_root_node())->get_node(NodePath(npath.get_concatenated_names())); StringName prop = npath.get_concatenated_subnames(); PropertyInfo prop_info; ClassDB::get_property_info(nd->get_class(), prop, &prop_info); @@ -4000,13 +4000,15 @@ Ref AnimationTrackEditor::_create_and_get_reset_animation() { return player->get_animation(SceneStringNames::get_singleton()->RESET); } else { Ref al; - if (!player->has_animation_library("")) { - al.instantiate(); - player->add_animation_library("", al); - } else { - al = player->get_animation_library(""); + AnimationMixer *mixer = AnimationPlayerEditor::get_singleton()->fetch_mixer_for_library(); + if (mixer) { + if (!mixer->has_animation_library("")) { + al.instantiate(); + mixer->add_animation_library("", al); + } else { + al = mixer->get_animation_library(""); + } } - Ref reset_anim; reset_anim.instantiate(); reset_anim->set_length(ANIM_MIN_LENGTH); @@ -4293,6 +4295,14 @@ void AnimationTrackEditor::show_select_node_warning(bool p_show) { info_message->set_visible(p_show); } +void AnimationTrackEditor::show_dummy_player_warning(bool p_show) { + dummy_player_warning->set_visible(p_show); +} + +void AnimationTrackEditor::show_inactive_player_warning(bool p_show) { + inactive_player_warning->set_visible(p_show); +} + bool AnimationTrackEditor::is_key_selected(int p_track, int p_key) const { SelectedKey sk; sk.key = p_key; @@ -4626,6 +4636,8 @@ void AnimationTrackEditor::_notification(int p_what) { view_group->set_icon(get_editor_theme_icon(view_group->is_pressed() ? SNAME("AnimationTrackList") : SNAME("AnimationTrackGroup"))); selected_filter->set_icon(get_editor_theme_icon(SNAME("AnimationFilter"))); imported_anim_warning->set_icon(get_editor_theme_icon(SNAME("NodeWarning"))); + dummy_player_warning->set_icon(get_editor_theme_icon(SNAME("NodeWarning"))); + inactive_player_warning->set_icon(get_editor_theme_icon(SNAME("NodeWarning"))); main_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); edit->get_popup()->set_item_icon(edit->get_popup()->get_item_index(EDIT_APPLY_RESET), get_editor_theme_icon(SNAME("Reload"))); } break; @@ -6303,8 +6315,17 @@ float AnimationTrackEditor::snap_time(float p_value, bool p_relative) { void AnimationTrackEditor::_show_imported_anim_warning() { // It looks terrible on a single line but the TTR extractor doesn't support line breaks yet. EditorNode::get_singleton()->show_warning( - TTR("This animation belongs to an imported scene, so changes to imported tracks will not be saved.\n\nTo modify this animation, navigate to the scene's Advanced Import settings and select the animation.\nSome options, including looping, are available here. To add custom tracks, enable \"Save To File\" and\n\"Keep Custom Tracks\"."), - TTR("Warning: Editing imported animation")); + TTR("This animation belongs to an imported scene, so changes to imported tracks will not be saved.\n\nTo modify this animation, navigate to the scene's Advanced Import settings and select the animation.\nSome options, including looping, are available here. To add custom tracks, enable \"Save To File\" and\n\"Keep Custom Tracks\".")); +} + +void AnimationTrackEditor::_show_dummy_player_warning() { + EditorNode::get_singleton()->show_warning( + TTR("Some AnimationPlayerEditor's options are disabled since this is the dummy AnimationPlayer for preview.\n\nThe dummy player is forced active, non-deterministic and doesn't have the root motion track. Furthermore, the original node is inactive temporary.")); +} + +void AnimationTrackEditor::_show_inactive_player_warning() { + EditorNode::get_singleton()->show_warning( + TTR("AnimationPlayer is inactive. The playback will not be processed.")); } void AnimationTrackEditor::_select_all_tracks_for_copy() { @@ -6489,6 +6510,20 @@ AnimationTrackEditor::AnimationTrackEditor() { imported_anim_warning->connect("pressed", callable_mp(this, &AnimationTrackEditor::_show_imported_anim_warning)); bottom_hb->add_child(imported_anim_warning); + dummy_player_warning = memnew(Button); + dummy_player_warning->hide(); + dummy_player_warning->set_text(TTR("Dummy Player")); + dummy_player_warning->set_tooltip_text(TTR("Warning: Editing dummy AnimationPlayer")); + dummy_player_warning->connect("pressed", callable_mp(this, &AnimationTrackEditor::_show_dummy_player_warning)); + bottom_hb->add_child(dummy_player_warning); + + inactive_player_warning = memnew(Button); + inactive_player_warning->hide(); + inactive_player_warning->set_text(TTR("Inactive Player")); + inactive_player_warning->set_tooltip_text(TTR("Warning: AnimationPlayer is inactive")); + inactive_player_warning->connect("pressed", callable_mp(this, &AnimationTrackEditor::_show_inactive_player_warning)); + bottom_hb->add_child(inactive_player_warning); + bottom_hb->add_spacer(); bezier_edit_icon = memnew(Button); diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index cef726f6c0..5327099517 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -387,6 +387,12 @@ class AnimationTrackEditor : public VBoxContainer { Button *imported_anim_warning = nullptr; void _show_imported_anim_warning(); + Button *dummy_player_warning = nullptr; + void _show_dummy_player_warning(); + + Button *inactive_player_warning = nullptr; + void _show_inactive_player_warning(); + void _snap_mode_changed(int p_mode); Vector track_edits; Vector groups; @@ -645,6 +651,8 @@ public: void commit_insert_queue(); void show_select_node_warning(bool p_show); + void show_dummy_player_warning(bool p_show); + void show_inactive_player_warning(bool p_show); bool is_key_selected(int p_track, int p_key) const; bool is_selection_active() const; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index b2763ab173..e69dcb2278 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -1701,16 +1701,19 @@ int EditorNode::_save_external_resources() { return saved; } -static void _reset_animation_players(Node *p_node, List> *r_anim_backups) { +static void _reset_animation_mixers(Node *p_node, List>> *r_anim_backups) { for (int i = 0; i < p_node->get_child_count(); i++) { - AnimationPlayer *player = Object::cast_to(p_node->get_child(i)); - if (player && player->is_reset_on_save_enabled() && player->can_apply_reset()) { - Ref old_values = player->apply_reset(); - if (old_values.is_valid()) { - r_anim_backups->push_back(old_values); + AnimationMixer *mixer = Object::cast_to(p_node->get_child(i)); + if (mixer && mixer->is_reset_on_save_enabled() && mixer->can_apply_reset()) { + Ref backup = mixer->apply_reset(); + if (backup.is_valid()) { + Pair> pair; + pair.first = mixer; + pair.second = backup; + r_anim_backups->push_back(pair); } } - _reset_animation_players(p_node->get_child(i), r_anim_backups); + _reset_animation_mixers(p_node->get_child(i), r_anim_backups); } } @@ -1730,8 +1733,8 @@ void EditorNode::_save_scene(String p_file, int idx) { scene->propagate_notification(NOTIFICATION_EDITOR_PRE_SAVE); editor_data.apply_changes_in_editors(); - List> anim_backups; - _reset_animation_players(scene, &anim_backups); + List>> anim_backups; + _reset_animation_mixers(scene, &anim_backups); save_default_environment(); _save_editor_states(p_file, idx); @@ -1773,8 +1776,8 @@ void EditorNode::_save_scene(String p_file, int idx) { _save_external_resources(); editor_data.save_editor_external_data(); - for (Ref &E : anim_backups) { - E->restore(); + for (Pair> &E : anim_backups) { + E.first->restore(E.second); } if (err == OK) { diff --git a/editor/gui/scene_tree_editor.cpp b/editor/gui/scene_tree_editor.cpp index fff4690445..26fdb74bd1 100644 --- a/editor/gui/scene_tree_editor.cpp +++ b/editor/gui/scene_tree_editor.cpp @@ -115,7 +115,7 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i } undo_redo->commit_action(); } else if (p_id == BUTTON_PIN) { - if (n->is_class("AnimationPlayer")) { + if (n->is_class("AnimationMixer")) { AnimationPlayerEditor::get_singleton()->unpin(); _update_tree(); } @@ -465,8 +465,8 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { } _update_visibility_color(p_node, item); - } else if (p_node->is_class("AnimationPlayer")) { - bool is_pinned = AnimationPlayerEditor::get_singleton()->get_player() == p_node && AnimationPlayerEditor::get_singleton()->is_pinned(); + } else if (p_node->is_class("AnimationMixer")) { + bool is_pinned = AnimationPlayerEditor::get_singleton()->get_editing_node() == p_node && AnimationPlayerEditor::get_singleton()->is_pinned(); if (is_pinned) { item->add_button(0, get_editor_theme_icon(SNAME("Pin")), BUTTON_PIN, false, TTR("AnimationPlayer is pinned.\nClick to unpin.")); diff --git a/editor/icons/AnimationMixer.svg b/editor/icons/AnimationMixer.svg new file mode 100644 index 0000000000..61f5bf6474 --- /dev/null +++ b/editor/icons/AnimationMixer.svg @@ -0,0 +1 @@ + diff --git a/editor/import/post_import_plugin_skeleton_renamer.cpp b/editor/import/post_import_plugin_skeleton_renamer.cpp index 59e07a7117..0c48c8ef76 100644 --- a/editor/import/post_import_plugin_skeleton_renamer.cpp +++ b/editor/import/post_import_plugin_skeleton_renamer.cpp @@ -102,7 +102,7 @@ void PostImportPluginSkeletonRenamer::_internal_process(InternalImportCategory p continue; } String track_path = String(anim->track_get_path(i).get_concatenated_names()); - Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path)); + Node *node = (ap->get_node(ap->get_root_node()))->get_node(NodePath(track_path)); if (node) { Skeleton3D *track_skeleton = Object::cast_to(node); if (track_skeleton && track_skeleton == skeleton) { @@ -219,8 +219,8 @@ void PostImportPluginSkeletonRenamer::internal_process(InternalImportCategory p_ int track_len = anim->get_track_count(); for (int i = 0; i < track_len; i++) { String track_path = String(anim->track_get_path(i).get_concatenated_names()); - Node *orig_node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path)); - Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path)); + Node *orig_node = (ap->get_node(ap->get_root_node()))->get_node(NodePath(track_path)); + Node *node = (ap->get_node(ap->get_root_node()))->get_node(NodePath(track_path)); while (node) { Skeleton3D *track_skeleton = Object::cast_to(node); if (track_skeleton && track_skeleton == skeleton) { diff --git a/editor/import/post_import_plugin_skeleton_rest_fixer.cpp b/editor/import/post_import_plugin_skeleton_rest_fixer.cpp index bffc100faf..cd31499b80 100644 --- a/editor/import/post_import_plugin_skeleton_rest_fixer.cpp +++ b/editor/import/post_import_plugin_skeleton_rest_fixer.cpp @@ -146,7 +146,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory } String track_path = String(anim->track_get_path(i).get_concatenated_names()); - Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path)); + Node *node = (ap->get_node(ap->get_root_node()))->get_node(NodePath(track_path)); ERR_CONTINUE(!node); Skeleton3D *track_skeleton = Object::cast_to(node); @@ -213,7 +213,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory continue; } track_path = String(anim->track_get_path(i).get_concatenated_names()); - Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path)); + Node *node = (ap->get_node(ap->get_root_node()))->get_node(NodePath(track_path)); if (node) { Skeleton3D *track_skeleton = Object::cast_to(node); if (track_skeleton && track_skeleton == src_skeleton) { @@ -388,7 +388,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory } String track_path = String(anim->track_get_path(i).get_concatenated_names()); - Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path)); + Node *node = (ap->get_node(ap->get_root_node()))->get_node(NodePath(track_path)); ERR_CONTINUE(!node); Skeleton3D *track_skeleton = Object::cast_to(node); @@ -448,7 +448,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory } String track_path = String(anim->track_get_path(i).get_concatenated_names()); - Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path)); + Node *node = (ap->get_node(ap->get_root_node()))->get_node(NodePath(track_path)); ERR_CONTINUE(!node); Skeleton3D *track_skeleton = Object::cast_to(node); @@ -544,7 +544,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory } String track_path = String(anim->track_get_path(i).get_concatenated_names()); - Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path)); + Node *node = (ap->get_node(ap->get_root_node()))->get_node(NodePath(track_path)); ERR_CONTINUE(!node); Skeleton3D *track_skeleton = Object::cast_to(node); diff --git a/editor/import/post_import_plugin_skeleton_track_organizer.cpp b/editor/import/post_import_plugin_skeleton_track_organizer.cpp index 829d97dea7..e5a8e879fc 100644 --- a/editor/import/post_import_plugin_skeleton_track_organizer.cpp +++ b/editor/import/post_import_plugin_skeleton_track_organizer.cpp @@ -78,7 +78,7 @@ void PostImportPluginSkeletonTrackOrganizer::internal_process(InternalImportCate Vector remove_indices; for (int i = 0; i < track_len; i++) { String track_path = String(anim->track_get_path(i).get_concatenated_names()); - Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path)); + Node *node = (ap->get_node(ap->get_root_node()))->get_node(NodePath(track_path)); if (!node) { if (remove_except_bone) { remove_indices.push_back(i); diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index 452a612753..2f889287f9 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -595,7 +595,7 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, HashMap(p_node); // Node paths in animation tracks are relative to the following path (this is used to fix node paths below). - Node *ap_root = ap->get_node(ap->get_root()); + Node *ap_root = ap->get_node(ap->get_root_node()); NodePath path_prefix = p_root->get_path_to(ap_root); bool nodes_were_renamed = r_node_renames.size() != 0; diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp index 89c21ddb68..184cc5302a 100644 --- a/editor/plugins/animation_blend_space_1d_editor.cpp +++ b/editor/plugins/animation_blend_space_1d_editor.cpp @@ -78,18 +78,12 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Refadd_submenu_item(TTR("Add Animation"), "animations"); - if (tree->has_node(tree->get_animation_player())) { - AnimationPlayer *ap = Object::cast_to(tree->get_node(tree->get_animation_player())); + List names; + tree->get_animation_list(&names); - if (ap) { - List names; - ap->get_animation_list(&names); - - for (const StringName &E : names) { - animations_menu->add_icon_item(get_editor_theme_icon(SNAME("Animation")), E); - animations_to_add.push_back(E); - } - } + for (const StringName &E : names) { + animations_menu->add_icon_item(get_editor_theme_icon(SNAME("Animation")), E); + animations_to_add.push_back(E); } for (const StringName &E : classes) { diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp index 3bc5e0c807..c987d7d6b6 100644 --- a/editor/plugins/animation_blend_space_2d_editor.cpp +++ b/editor/plugins/animation_blend_space_2d_editor.cpp @@ -123,16 +123,11 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Refadd_submenu_item(TTR("Add Animation"), "animations"); - if (tree->has_node(tree->get_animation_player())) { - AnimationPlayer *ap = Object::cast_to(tree->get_node(tree->get_animation_player())); - if (ap) { - List names; - ap->get_animation_list(&names); - for (const StringName &E : names) { - animations_menu->add_icon_item(get_editor_theme_icon(SNAME("Animation")), E); - animations_to_add.push_back(E); - } - } + List names; + tree->get_animation_list(&names); + for (const StringName &E : names) { + animations_menu->add_icon_item(get_editor_theme_icon(SNAME("Animation")), E); + animations_to_add.push_back(E); } for (const StringName &E : classes) { diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index 157278e4bc..dc3729393f 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -238,21 +238,16 @@ void AnimationNodeBlendTreeEditor::update_graph() { ProgressBar *pb = memnew(ProgressBar); - if (tree->has_node(tree->get_animation_player())) { - AnimationPlayer *ap = Object::cast_to(tree->get_node(tree->get_animation_player())); - if (ap) { - List anims; - ap->get_animation_list(&anims); - - for (const StringName &F : anims) { - mb->get_popup()->add_item(F); - options.push_back(F); - } + List anims; + tree->get_animation_list(&anims); - if (ap->has_animation(anim->get_animation())) { - pb->set_max(ap->get_animation(anim->get_animation())->get_length()); - } - } + for (const StringName &F : anims) { + mb->get_popup()->add_item(F); + options.push_back(F); + } + + if (tree->has_animation(anim->get_animation())) { + pb->set_max(tree->get_animation(anim->get_animation())->get_length()); } pb->set_show_percentage(false); @@ -625,21 +620,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref &ano return false; } - NodePath player_path = tree->get_animation_player(); - - if (!tree->has_node(player_path)) { - EditorNode::get_singleton()->show_warning(TTR("No animation player set, so unable to retrieve track names.")); - return false; - } - - AnimationPlayer *player = Object::cast_to(tree->get_node(player_path)); - if (!player) { - EditorNode::get_singleton()->show_warning(TTR("Player path set is invalid, so unable to retrieve track names.")); - return false; - } - - Node *base = player->get_node(player->get_root()); - + Node *base = tree->get_node(tree->get_root_node()); if (!base) { EditorNode::get_singleton()->show_warning(TTR("Animation player has no valid root node path, so unable to retrieve track names.")); return false; @@ -651,10 +632,10 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref &ano HashMap> types; { List animation_list; - player->get_animation_list(&animation_list); + tree->get_animation_list(&animation_list); for (const StringName &E : animation_list) { - Ref anim = player->get_animation(E); + Ref anim = tree->get_animation(E); for (int i = 0; i < anim->get_track_count(); i++) { String track_path = anim->track_get_path(i); paths.insert(track_path); @@ -885,23 +866,16 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) { graph->set_connection_activity(E.output_node, 0, E.input_node, E.input_index, activity); } - AnimationPlayer *player = nullptr; - if (tree->has_node(tree->get_animation_player())) { - player = Object::cast_to(tree->get_node(tree->get_animation_player())); - } - - if (player) { - for (const KeyValue &E : animations) { - Ref an = blend_tree->get_node(E.key); - if (an.is_valid()) { - if (player->has_animation(an->get_animation())) { - Ref anim = player->get_animation(an->get_animation()); - if (anim.is_valid()) { - E.value->set_max(anim->get_length()); - //StringName path = AnimationTreeEditor::get_singleton()->get_base_path() + E.input_node; - StringName time_path = AnimationTreeEditor::get_singleton()->get_base_path() + String(E.key) + "/time"; - E.value->set_value(tree->get(time_path)); - } + for (const KeyValue &E : animations) { + Ref an = blend_tree->get_node(E.key); + if (an.is_valid()) { + if (tree->has_animation(an->get_animation())) { + Ref anim = tree->get_animation(an->get_animation()); + if (anim.is_valid()) { + E.value->set_max(anim->get_length()); + //StringName path = AnimationTreeEditor::get_singleton()->get_base_path() + E.input_node; + StringName time_path = AnimationTreeEditor::get_singleton()->get_base_path() + String(E.key) + "/time"; + E.value->set_value(tree->get(time_path)); } } } diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp index 6a54bc654f..c4c0799daa 100644 --- a/editor/plugins/animation_library_editor.cpp +++ b/editor/plugins/animation_library_editor.cpp @@ -36,8 +36,8 @@ #include "editor/editor_undo_redo_manager.h" #include "editor/gui/editor_file_dialog.h" -void AnimationLibraryEditor::set_animation_player(Object *p_player) { - player = p_player; +void AnimationLibraryEditor::set_animation_mixer(Object *p_mixer) { + mixer = p_mixer; } void AnimationLibraryEditor::_add_library() { @@ -54,7 +54,7 @@ void AnimationLibraryEditor::_add_library_validate(const String &p_name) { String error; if (adding_animation) { - Ref al = player->call("get_animation_library", adding_animation_to_library); + Ref al = mixer->call("get_animation_library", adding_animation_to_library); ERR_FAIL_COND(al.is_null()); if (p_name == "") { error = TTR("Animation name can't be empty."); @@ -64,11 +64,11 @@ void AnimationLibraryEditor::_add_library_validate(const String &p_name) { error = TTR("Animation with the same name already exists."); } } else { - if (p_name == "" && bool(player->call("has_animation_library", ""))) { + if (p_name == "" && bool(mixer->call("has_animation_library", ""))) { error = TTR("Enter a library name."); } else if (!AnimationLibrary::is_valid_library_name(p_name)) { error = TTR("Library name contains invalid characters: '/', ':', ',' or '['."); - } else if (bool(player->call("has_animation_library", p_name))) { + } else if (bool(mixer->call("has_animation_library", p_name))) { error = TTR("Library with the same name already exists."); } } @@ -97,7 +97,7 @@ void AnimationLibraryEditor::_add_library_confirm() { String anim_name = add_library_name->get_text(); EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - Ref al = player->call("get_animation_library", adding_animation_to_library); + Ref al = mixer->call("get_animation_library", adding_animation_to_library); ERR_FAIL_COND(!al.is_valid()); Ref anim; @@ -106,8 +106,8 @@ void AnimationLibraryEditor::_add_library_confirm() { undo_redo->create_action(vformat(TTR("Add Animation to Library: %s"), anim_name)); undo_redo->add_do_method(al.ptr(), "add_animation", anim_name, anim); undo_redo->add_undo_method(al.ptr(), "remove_animation", anim_name); - undo_redo->add_do_method(this, "_update_editor", player); - undo_redo->add_undo_method(this, "_update_editor", player); + undo_redo->add_do_method(this, "_update_editor", mixer); + undo_redo->add_undo_method(this, "_update_editor", mixer); undo_redo->commit_action(); } else { @@ -118,10 +118,10 @@ void AnimationLibraryEditor::_add_library_confirm() { al.instantiate(); undo_redo->create_action(vformat(TTR("Add Animation Library: %s"), lib_name)); - undo_redo->add_do_method(player, "add_animation_library", lib_name, al); - undo_redo->add_undo_method(player, "remove_animation_library", lib_name); - undo_redo->add_do_method(this, "_update_editor", player); - undo_redo->add_undo_method(this, "_update_editor", player); + undo_redo->add_do_method(mixer, "add_animation_library", lib_name, al); + undo_redo->add_undo_method(mixer, "remove_animation_library", lib_name); + undo_redo->add_do_method(this, "_update_editor", mixer); + undo_redo->add_undo_method(this, "_update_editor", mixer); undo_redo->commit_action(); } } @@ -144,7 +144,7 @@ void AnimationLibraryEditor::_load_library() { } void AnimationLibraryEditor::_file_popup_selected(int p_id) { - Ref al = player->call("get_animation_library", file_dialog_library); + Ref al = mixer->call("get_animation_library", file_dialog_library); Ref anim; if (file_dialog_animation != StringName()) { anim = al->get_animation(file_dialog_animation); @@ -214,12 +214,12 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(vformat(TTR("Make Animation Library Unique: %s"), lib_name)); - undo_redo->add_do_method(player, "remove_animation_library", lib_name); - undo_redo->add_do_method(player, "add_animation_library", lib_name, ald); - undo_redo->add_undo_method(player, "remove_animation_library", lib_name); - undo_redo->add_undo_method(player, "add_animation_library", lib_name, al); - undo_redo->add_do_method(this, "_update_editor", player); - undo_redo->add_undo_method(this, "_update_editor", player); + undo_redo->add_do_method(mixer, "remove_animation_library", lib_name); + undo_redo->add_do_method(mixer, "add_animation_library", lib_name, ald); + undo_redo->add_undo_method(mixer, "remove_animation_library", lib_name); + undo_redo->add_undo_method(mixer, "add_animation_library", lib_name, al); + undo_redo->add_do_method(this, "_update_editor", mixer); + undo_redo->add_undo_method(this, "_update_editor", mixer); undo_redo->commit_action(); update_tree(); @@ -287,8 +287,8 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) { undo_redo->add_do_method(al.ptr(), "add_animation", anim_name, animd); undo_redo->add_undo_method(al.ptr(), "remove_animation", anim_name); undo_redo->add_undo_method(al.ptr(), "add_animation", anim_name, anim); - undo_redo->add_do_method(this, "_update_editor", player); - undo_redo->add_undo_method(this, "_update_editor", player); + undo_redo->add_do_method(this, "_update_editor", mixer); + undo_redo->add_undo_method(this, "_update_editor", mixer); undo_redo->commit_action(); update_tree(); @@ -308,12 +308,12 @@ void AnimationLibraryEditor::_load_file(String p_path) { return; } - TypedArray libs = player->call("get_animation_library_list"); + TypedArray libs = mixer->call("get_animation_library_list"); for (int i = 0; i < libs.size(); i++) { const StringName K = libs[i]; - Ref al2 = player->call("get_animation_library", K); + Ref al2 = mixer->call("get_animation_library", K); if (al2 == al) { - error_dialog->set_text(TTR("This library is already added to the player.")); + error_dialog->set_text(TTR("This library is already added to the mixer.")); error_dialog->popup_centered(); return; @@ -324,7 +324,7 @@ void AnimationLibraryEditor::_load_file(String p_path) { int attempt = 1; - while (bool(player->call("has_animation_library", name))) { + while (bool(mixer->call("has_animation_library", name))) { attempt++; name = p_path.get_file().get_basename() + " " + itos(attempt); } @@ -332,10 +332,10 @@ void AnimationLibraryEditor::_load_file(String p_path) { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(vformat(TTR("Add Animation Library: %s"), name)); - undo_redo->add_do_method(player, "add_animation_library", name, al); - undo_redo->add_undo_method(player, "remove_animation_library", name); - undo_redo->add_do_method(this, "_update_editor", player); - undo_redo->add_undo_method(this, "_update_editor", player); + undo_redo->add_do_method(mixer, "add_animation_library", name, al); + undo_redo->add_undo_method(mixer, "remove_animation_library", name); + undo_redo->add_do_method(this, "_update_editor", mixer); + undo_redo->add_undo_method(this, "_update_editor", mixer); undo_redo->commit_action(); } break; case FILE_DIALOG_ACTION_OPEN_ANIMATION: { @@ -346,7 +346,7 @@ void AnimationLibraryEditor::_load_file(String p_path) { return; } - Ref al = player->call("get_animation_library", adding_animation_to_library); + Ref al = mixer->call("get_animation_library", adding_animation_to_library); List anims; al->get_animation_list(&anims); for (const StringName &K : anims) { @@ -372,13 +372,13 @@ void AnimationLibraryEditor::_load_file(String p_path) { undo_redo->create_action(vformat(TTR("Load Animation into Library: %s"), name)); undo_redo->add_do_method(al.ptr(), "add_animation", name, anim); undo_redo->add_undo_method(al.ptr(), "remove_animation", name); - undo_redo->add_do_method(this, "_update_editor", player); - undo_redo->add_undo_method(this, "_update_editor", player); + undo_redo->add_do_method(this, "_update_editor", mixer); + undo_redo->add_undo_method(this, "_update_editor", mixer); undo_redo->commit_action(); } break; case FILE_DIALOG_ACTION_SAVE_LIBRARY: { - Ref al = player->call("get_animation_library", file_dialog_library); + Ref al = mixer->call("get_animation_library", file_dialog_library); String prev_path = al->get_path(); EditorNode::get_singleton()->save_resource_in_path(al, p_path); @@ -388,14 +388,14 @@ void AnimationLibraryEditor::_load_file(String p_path) { undo_redo->create_action(vformat(TTR("Save Animation library to File: %s"), file_dialog_library)); undo_redo->add_do_method(al.ptr(), "set_path", al->get_path()); undo_redo->add_undo_method(al.ptr(), "set_path", prev_path); - undo_redo->add_do_method(this, "_update_editor", player); - undo_redo->add_undo_method(this, "_update_editor", player); + undo_redo->add_do_method(this, "_update_editor", mixer); + undo_redo->add_undo_method(this, "_update_editor", mixer); undo_redo->commit_action(); } } break; case FILE_DIALOG_ACTION_SAVE_ANIMATION: { - Ref al = player->call("get_animation_library", file_dialog_library); + Ref al = mixer->call("get_animation_library", file_dialog_library); Ref anim; if (file_dialog_animation != StringName()) { anim = al->get_animation(file_dialog_animation); @@ -409,8 +409,8 @@ void AnimationLibraryEditor::_load_file(String p_path) { undo_redo->create_action(vformat(TTR("Save Animation to File: %s"), file_dialog_animation)); undo_redo->add_do_method(anim.ptr(), "set_path", anim->get_path()); undo_redo->add_undo_method(anim.ptr(), "set_path", prev_path); - undo_redo->add_do_method(this, "_update_editor", player); - undo_redo->add_undo_method(this, "_update_editor", player); + undo_redo->add_do_method(this, "_update_editor", mixer); + undo_redo->add_undo_method(this, "_update_editor", mixer); undo_redo->commit_action(); } } break; @@ -430,14 +430,14 @@ void AnimationLibraryEditor::_item_renamed() { if (ti->get_parent() == tree->get_root()) { // Renamed library - if (player->call("has_animation_library", text)) { + if (mixer->call("has_animation_library", text)) { restore_text = true; } else { undo_redo->create_action(vformat(TTR("Rename Animation Library: %s"), text)); - undo_redo->add_do_method(player, "rename_animation_library", old_text, text); - undo_redo->add_undo_method(player, "rename_animation_library", text, old_text); - undo_redo->add_do_method(this, "_update_editor", player); - undo_redo->add_undo_method(this, "_update_editor", player); + undo_redo->add_do_method(mixer, "rename_animation_library", old_text, text); + undo_redo->add_undo_method(mixer, "rename_animation_library", text, old_text); + undo_redo->add_do_method(this, "_update_editor", mixer); + undo_redo->add_undo_method(this, "_update_editor", mixer); updating = true; undo_redo->commit_action(); updating = false; @@ -451,7 +451,7 @@ void AnimationLibraryEditor::_item_renamed() { } else { // Renamed anim StringName library = ti->get_parent()->get_metadata(0); - Ref al = player->call("get_animation_library", library); + Ref al = mixer->call("get_animation_library", library); if (al.is_valid()) { if (al->has_animation(text)) { @@ -460,8 +460,8 @@ void AnimationLibraryEditor::_item_renamed() { undo_redo->create_action(vformat(TTR("Rename Animation: %s"), text)); undo_redo->add_do_method(al.ptr(), "rename_animation", old_text, text); undo_redo->add_undo_method(al.ptr(), "rename_animation", text, old_text); - undo_redo->add_do_method(this, "_update_editor", player); - undo_redo->add_undo_method(this, "_update_editor", player); + undo_redo->add_do_method(this, "_update_editor", mixer); + undo_redo->add_undo_method(this, "_update_editor", mixer); updating = true; undo_redo->commit_action(); updating = false; @@ -483,7 +483,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int if (p_item->get_parent() == tree->get_root()) { // Library StringName lib_name = p_item->get_metadata(0); - Ref al = player->call("get_animation_library", lib_name); + Ref al = mixer->call("get_animation_library", lib_name); switch (p_id) { case LIB_BUTTON_ADD: { add_library_dialog->set_title(TTR("Animation Name:")); @@ -541,8 +541,8 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int undo_redo->create_action(vformat(TTR("Add Animation to Library: %s"), name)); undo_redo->add_do_method(al.ptr(), "add_animation", name, anim); undo_redo->add_undo_method(al.ptr(), "remove_animation", name); - undo_redo->add_do_method(this, "_update_editor", player); - undo_redo->add_undo_method(this, "_update_editor", player); + undo_redo->add_do_method(this, "_update_editor", mixer); + undo_redo->add_undo_method(this, "_update_editor", mixer); undo_redo->commit_action(); } break; @@ -564,10 +564,10 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int case LIB_BUTTON_DELETE: { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(vformat(TTR("Remove Animation Library: %s"), lib_name)); - undo_redo->add_do_method(player, "remove_animation_library", lib_name); - undo_redo->add_undo_method(player, "add_animation_library", lib_name, al); - undo_redo->add_do_method(this, "_update_editor", player); - undo_redo->add_undo_method(this, "_update_editor", player); + undo_redo->add_do_method(mixer, "remove_animation_library", lib_name); + undo_redo->add_undo_method(mixer, "add_animation_library", lib_name, al); + undo_redo->add_do_method(this, "_update_editor", mixer); + undo_redo->add_undo_method(this, "_update_editor", mixer); undo_redo->commit_action(); } break; } @@ -576,7 +576,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int // Animation StringName lib_name = p_item->get_parent()->get_metadata(0); StringName anim_name = p_item->get_metadata(0); - Ref al = player->call("get_animation_library", lib_name); + Ref al = mixer->call("get_animation_library", lib_name); Ref anim = al->get_animation(anim_name); ERR_FAIL_COND(!anim.is_valid()); switch (p_id) { @@ -607,8 +607,8 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int undo_redo->create_action(vformat(TTR("Remove Animation from Library: %s"), anim_name)); undo_redo->add_do_method(al.ptr(), "remove_animation", anim_name); undo_redo->add_undo_method(al.ptr(), "add_animation", anim_name, anim); - undo_redo->add_do_method(this, "_update_editor", player); - undo_redo->add_undo_method(this, "_update_editor", player); + undo_redo->add_do_method(this, "_update_editor", mixer); + undo_redo->add_undo_method(this, "_update_editor", mixer); undo_redo->commit_action(); } break; } @@ -621,12 +621,12 @@ void AnimationLibraryEditor::update_tree() { } tree->clear(); - ERR_FAIL_NULL(player); + ERR_FAIL_NULL(mixer); Color ss_color = get_theme_color(SNAME("prop_subsection"), EditorStringName(Editor)); TreeItem *root = tree->create_item(); - TypedArray libs = player->call("get_animation_library_list"); + TypedArray libs = mixer->call("get_animation_library_list"); for (int i = 0; i < libs.size(); i++) { const StringName K = libs[i]; @@ -638,7 +638,7 @@ void AnimationLibraryEditor::update_tree() { libitem->set_suffix(0, ""); } - Ref al = player->call("get_animation_library", K); + Ref al = mixer->call("get_animation_library", K); bool animation_library_is_foreign = false; String al_path = al->get_path(); if (!al_path.is_resource_file()) { @@ -727,12 +727,12 @@ void AnimationLibraryEditor::show_dialog() { popup_centered_ratio(0.5); } -void AnimationLibraryEditor::_update_editor(Object *p_player) { - emit_signal("update_editor", p_player); +void AnimationLibraryEditor::_update_editor(Object *p_mixer) { + emit_signal("update_editor", p_mixer); } void AnimationLibraryEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("_update_editor", "player"), &AnimationLibraryEditor::_update_editor); + ClassDB::bind_method(D_METHOD("_update_editor", "mixer"), &AnimationLibraryEditor::_update_editor); ADD_SIGNAL(MethodInfo("update_editor")); } diff --git a/editor/plugins/animation_library_editor.h b/editor/plugins/animation_library_editor.h index a9b2c72b9d..49a5c786d3 100644 --- a/editor/plugins/animation_library_editor.h +++ b/editor/plugins/animation_library_editor.h @@ -33,7 +33,7 @@ #include "editor/animation_track_editor.h" #include "editor/editor_plugin.h" -#include "scene/animation/animation_player.h" +#include "scene/animation/animation_mixer.h" #include "scene/gui/dialogs.h" #include "scene/gui/tree.h" @@ -90,7 +90,7 @@ class AnimationLibraryEditor : public AcceptDialog { Tree *tree = nullptr; - Object *player = nullptr; + Object *mixer = nullptr; void _add_library(); void _add_library_validate(const String &p_name); @@ -106,11 +106,11 @@ class AnimationLibraryEditor : public AcceptDialog { bool updating = false; protected: - void _update_editor(Object *p_player); + void _update_editor(Object *p_mixer); static void _bind_methods(); public: - void set_animation_player(Object *p_player); + void set_animation_mixer(Object *p_mixer); void show_dialog(); void update_tree(); AnimationLibraryEditor(); diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 51d195e0e1..f2225fabad 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -44,6 +44,7 @@ #include "editor/plugins/canvas_item_editor_plugin.h" // For onion skinning. #include "editor/plugins/node_3d_editor_plugin.h" // For onion skinning. #include "editor/scene_tree_dock.h" +#include "scene/animation/animation_tree.h" #include "scene/gui/separator.h" #include "scene/main/window.h" #include "scene/resources/animation.h" @@ -54,7 +55,11 @@ /////////////////////////////////// void AnimationPlayerEditor::_node_removed(Node *p_node) { - if (player && player == p_node) { + if (player && original_node == p_node) { + if (is_dummy) { + plugin->_clear_dummy_player(); + } + player = nullptr; set_process(false); @@ -63,12 +68,20 @@ void AnimationPlayerEditor::_node_removed(Node *p_node) { track_editor->set_root(nullptr); track_editor->show_select_node_warning(true); _update_player(); + + _ensure_dummy_player(); } } void AnimationPlayerEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_PROCESS: { + if (!player || is_dummy) { + track_editor->show_inactive_player_warning(false); + } else { + track_editor->show_inactive_player_warning(!player->is_active()); + } + if (!player) { return; } @@ -103,13 +116,13 @@ void AnimationPlayerEditor::_notification(int p_what) { } break; case NOTIFICATION_ENTER_TREE: { - tool_anim->get_popup()->connect("id_pressed", callable_mp(this, &AnimationPlayerEditor::_animation_tool_menu)); + tool_anim->get_popup()->connect(SNAME("id_pressed"), callable_mp(this, &AnimationPlayerEditor::_animation_tool_menu)); - onion_skinning->get_popup()->connect("id_pressed", callable_mp(this, &AnimationPlayerEditor::_onion_skinning_menu)); + onion_skinning->get_popup()->connect(SNAME("id_pressed"), callable_mp(this, &AnimationPlayerEditor::_onion_skinning_menu)); - blend_editor.next->connect("item_selected", callable_mp(this, &AnimationPlayerEditor::_blend_editor_next_changed)); + blend_editor.next->connect(SNAME("item_selected"), callable_mp(this, &AnimationPlayerEditor::_blend_editor_next_changed)); - get_tree()->connect("node_removed", callable_mp(this, &AnimationPlayerEditor::_node_removed)); + get_tree()->connect(SNAME("node_removed"), callable_mp(this, &AnimationPlayerEditor::_node_removed)); add_theme_style_override("panel", EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("panel"), SNAME("Panel"))); } break; @@ -167,6 +180,10 @@ void AnimationPlayerEditor::_notification(int p_what) { _update_animation_list_icons(); } break; + + case NOTIFICATION_VISIBILITY_CHANGED: { + _ensure_dummy_player(); + } break; } } @@ -303,20 +320,19 @@ void AnimationPlayerEditor::_animation_selected(int p_which) { bool animation_library_is_foreign = EditorNode::get_singleton()->is_resource_read_only(anim); track_editor->set_animation(anim, animation_library_is_foreign); - Node *root = player->get_node(player->get_root()); + Node *root = player->get_node_or_null(player->get_root_node()); if (root) { track_editor->set_root(root); } } frame->set_max((double)anim->get_length()); - + autoplay->set_pressed(current == player->get_autoplay()); } else { track_editor->set_animation(Ref(), true); track_editor->set_root(nullptr); + autoplay->set_pressed(false); } - autoplay->set_pressed(current == player->get_autoplay()); - AnimationPlayerEditor::get_singleton()->get_track_editor()->update_keying(); _animation_key_editor_seek(timeline_position, false); @@ -506,6 +522,9 @@ void AnimationPlayerEditor::_animation_name_edited() { undo_redo->add_undo_method(this, "_animation_player_changed", player); undo_redo->commit_action(); + if (is_dummy) { + plugin->_update_dummy_player(original_node); + } _select_anim_by_name(new_library_prefix + new_name); } break; @@ -534,7 +553,7 @@ void AnimationPlayerEditor::_animation_name_edited() { if (al.is_null()) { al.instantiate(); lib_added = true; - undo_redo->add_do_method(player, "add_animation_library", "", al); + undo_redo->add_do_method(fetch_mixer_for_library(), "add_animation_library", "", al); library_name = ""; } @@ -547,13 +566,17 @@ void AnimationPlayerEditor::_animation_name_edited() { undo_redo->add_undo_method(this, "_stop_onion_skinning"); } if (lib_added) { - undo_redo->add_undo_method(player, "remove_animation_library", ""); + undo_redo->add_undo_method(fetch_mixer_for_library(), "remove_animation_library", ""); } undo_redo->commit_action(); if (library_name != "") { library_name = library_name + "/"; } + + if (is_dummy) { + plugin->_update_dummy_player(original_node); + } _select_anim_by_name(library_name + new_name); } break; @@ -602,6 +625,10 @@ void AnimationPlayerEditor::_animation_name_edited() { if (library_name != "") { library_name = library_name + "/"; } + + if (is_dummy) { + plugin->_update_dummy_player(original_node); + } _select_anim_by_name(library_name + new_name); } break; } @@ -714,7 +741,7 @@ void AnimationPlayerEditor::_blend_edited() { } void AnimationPlayerEditor::ensure_visibility() { - if (player && pin->is_pressed()) { + if (player) { return; // another player is pinned, don't reset } @@ -724,11 +751,13 @@ void AnimationPlayerEditor::ensure_visibility() { Dictionary AnimationPlayerEditor::get_state() const { Dictionary d; - d["visible"] = is_visible_in_tree(); - if (EditorNode::get_singleton()->get_edited_scene() && is_visible_in_tree() && player) { - d["player"] = EditorNode::get_singleton()->get_edited_scene()->get_path_to(player); - d["animation"] = player->get_assigned_animation(); - d["track_editor_state"] = track_editor->get_state(); + if (!is_dummy) { + d["visible"] = is_visible_in_tree(); + if (EditorNode::get_singleton()->get_edited_scene() && is_visible_in_tree() && player) { + d["player"] = EditorNode::get_singleton()->get_edited_scene()->get_path_to(player); + d["animation"] = player->get_assigned_animation(); + d["track_editor_state"] = track_editor->get_state(); + } } return d; @@ -746,14 +775,20 @@ void AnimationPlayerEditor::set_state(const Dictionary &p_state) { Node *n = EditorNode::get_singleton()->get_edited_scene()->get_node(p_state["player"]); if (Object::cast_to(n) && EditorNode::get_singleton()->get_editor_selection()->is_selected(n)) { if (player) { - if (player->is_connected("animation_libraries_updated", callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated))) { - player->disconnect("animation_libraries_updated", callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated)); + if (player->is_connected(SNAME("animation_list_changed"), callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated))) { + player->disconnect(SNAME("animation_list_changed"), callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated)); + } + if (player->is_connected(SNAME("current_animation_changed"), callable_mp(this, &AnimationPlayerEditor::_current_animation_changed))) { + player->disconnect(SNAME("current_animation_changed"), callable_mp(this, &AnimationPlayerEditor::_current_animation_changed)); } } player = Object::cast_to(n); if (player) { - if (!player->is_connected("animation_libraries_updated", callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated))) { - player->connect("animation_libraries_updated", callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated)); + if (!player->is_connected(SNAME("animation_list_changed"), callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated))) { + player->connect(SNAME("animation_list_changed"), callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated), CONNECT_DEFERRED); + } + if (!player->is_connected(SNAME("current_animation_changed"), callable_mp(this, &AnimationPlayerEditor::_current_animation_changed))) { + player->connect(SNAME("current_animation_changed"), callable_mp(this, &AnimationPlayerEditor::_current_animation_changed), CONNECT_DEFERRED); } } @@ -794,7 +829,7 @@ void AnimationPlayerEditor::_animation_edit() { track_editor->set_animation(anim, animation_library_is_foreign); - Node *root = player->get_node(player->get_root()); + Node *root = player->get_node_or_null(player->get_root_node()); if (root) { track_editor->set_root(root); } @@ -935,7 +970,7 @@ void AnimationPlayerEditor::_update_player() { bool animation_library_is_foreign = EditorNode::get_singleton()->is_resource_read_only(anim); track_editor->set_animation(anim, animation_library_is_foreign); - Node *root = player->get_node(player->get_root()); + Node *root = player->get_node_or_null(player->get_root_node()); if (root) { track_editor->set_root(root); } @@ -1007,21 +1042,69 @@ void AnimationPlayerEditor::_update_name_dialog_library_dropdown() { } } -void AnimationPlayerEditor::edit(AnimationPlayer *p_player) { +void AnimationPlayerEditor::_ensure_dummy_player() { + bool dummy_exists = is_dummy && player && original_node; + if (dummy_exists) { + if (is_visible()) { + player->set_active(true); + original_node->set_editing(true); + } else { + player->set_active(false); + original_node->set_editing(false); + } + } + + // Make some options disabled. + tool_anim->get_popup()->set_item_disabled(tool_anim->get_popup()->get_item_index(TOOL_EDIT_TRANSITIONS), dummy_exists); + onion_toggle->set_disabled(dummy_exists); + onion_skinning->set_disabled(dummy_exists); + int selected = animation->get_selected(); + autoplay->set_disabled(selected != -1 ? (animation->get_item_text(selected).is_empty() ? true : dummy_exists) : true); + + // Show warning. + if (track_editor) { + track_editor->show_dummy_player_warning(dummy_exists); + } +} + +void AnimationPlayerEditor::edit(AnimationMixer *p_node, AnimationPlayer *p_player, bool p_is_dummy) { if (player && pin->is_pressed()) { return; // Ignore, pinned. } if (player) { - if (player->is_connected("animation_libraries_updated", callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated))) { - player->disconnect("animation_libraries_updated", callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated)); + if (player->is_connected(SNAME("animation_list_changed"), callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated))) { + player->disconnect(SNAME("animation_list_changed"), callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated)); + } + if (player->is_connected(SNAME("current_animation_changed"), callable_mp(this, &AnimationPlayerEditor::_current_animation_changed))) { + player->disconnect(SNAME("current_animation_changed"), callable_mp(this, &AnimationPlayerEditor::_current_animation_changed)); } } + + AnimationTree *tree = Object::cast_to(p_node); + + if (tree) { + if (tree->is_connected(SNAME("animation_player_changed"), callable_mp(this, &AnimationPlayerEditor::unpin))) { + tree->disconnect(SNAME("animation_player_changed"), callable_mp(this, &AnimationPlayerEditor::unpin)); + } + } + + original_node = p_node; player = p_player; + is_dummy = p_is_dummy; + + if (tree) { + if (!tree->is_connected(SNAME("animation_player_changed"), callable_mp(this, &AnimationPlayerEditor::unpin))) { + tree->connect(SNAME("animation_player_changed"), callable_mp(this, &AnimationPlayerEditor::unpin)); + } + } if (player) { - if (!player->is_connected("animation_libraries_updated", callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated))) { - player->connect("animation_libraries_updated", callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated)); + if (!player->is_connected(SNAME("animation_list_changed"), callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated))) { + player->connect(SNAME("animation_list_changed"), callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated), CONNECT_DEFERRED); + } + if (!player->is_connected(SNAME("current_animation_changed"), callable_mp(this, &AnimationPlayerEditor::_current_animation_changed))) { + player->connect(SNAME("current_animation_changed"), callable_mp(this, &AnimationPlayerEditor::_current_animation_changed)); } _update_player(); @@ -1042,7 +1125,9 @@ void AnimationPlayerEditor::edit(AnimationPlayer *p_player) { track_editor->show_select_node_warning(true); } - library_editor->set_animation_player(player); + library_editor->set_animation_mixer(fetch_mixer_for_library()); + + _ensure_dummy_player(); } void AnimationPlayerEditor::forward_force_draw_over_viewport(Control *p_overlay) { @@ -1181,12 +1266,12 @@ void AnimationPlayerEditor::_seek_value_changed(float p_value, bool p_set, bool if (!p_timeline_only) { if (player->is_valid() && !p_set) { - float cpos = player->get_current_animation_position(); - - player->seek_delta(pos, pos - cpos); + double delta = pos - player->get_current_animation_position(); + player->seek(pos, true, true); + player->seek(pos + delta, true, true); } else { player->stop(); - player->seek(pos, true); + player->seek(pos, true, true); } } @@ -1194,14 +1279,12 @@ void AnimationPlayerEditor::_seek_value_changed(float p_value, bool p_set, bool }; void AnimationPlayerEditor::_animation_player_changed(Object *p_pl) { - if (player == p_pl && is_visible_in_tree()) { - _update_player(); - if (blend_editor.dialog->is_visible()) { - _animation_blend(); // Update. - } - if (library_editor->is_visible()) { - library_editor->update_tree(); - } + _update_player(); + if (blend_editor.dialog->is_visible()) { + _animation_blend(); // Update. + } + if (library_editor->is_visible()) { + library_editor->update_tree(); } } @@ -1215,6 +1298,25 @@ void AnimationPlayerEditor::_list_changed() { } } +void AnimationPlayerEditor::_current_animation_changed(const String &p_name) { + if (is_visible_in_tree()) { + if (p_name.is_empty()) { + // Means [stop]. + frame->set_value(0); + track_editor->set_anim_pos(0); + _update_animation(); + return; + } + Ref anim = player->get_animation(p_name); + if (anim.is_null()) { + return; + } + bool animation_library_is_foreign = EditorNode::get_singleton()->is_resource_read_only(anim); + track_editor->set_animation(anim, animation_library_is_foreign); + _update_animation(); + } +} + void AnimationPlayerEditor::_animation_key_editor_anim_len_changed(float p_len) { frame->set_max(p_len); } @@ -1257,7 +1359,7 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) { _animation_new(); } break; case TOOL_ANIM_LIBRARY: { - library_editor->set_animation_player(player); + library_editor->set_animation_mixer(fetch_mixer_for_library()); library_editor->show_dialog(); } break; case TOOL_DUPLICATE_ANIM: { @@ -1267,6 +1369,9 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) { _animation_rename(); } break; case TOOL_EDIT_TRANSITIONS: { + if (is_dummy) { + break; + } _animation_blend(); } break; case TOOL_REMOVE_ANIM: { @@ -1506,7 +1611,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { } // Backup current animation state. - Ref values_backup = player->backup_animated_values(); + Ref backup_current = player->make_backup(); float cpos = player->get_current_animation_position(); // Render every past/future step with the capture shader. @@ -1536,7 +1641,6 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { if (valid) { player->seek(pos, true); get_tree()->flush_transform_notifications(); // Needed for transforms of Node3Ds. - values_backup->update_skeletons(); // Needed for Skeletons (2D & 3D). RS::get_singleton()->viewport_set_active(onion.captures[cidx], true); RS::get_singleton()->viewport_set_parent_viewport(root_vp, onion.captures[cidx]); @@ -1556,7 +1660,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { // (Seeking with update=true wouldn't do the trick because the current value of the properties // may not match their value for the current point in the animation). player->seek(cpos, false); - values_backup->restore(); + player->restore(backup_current); // Restore state of main editors. if (Node3DEditor::get_singleton()->is_visible()) { @@ -1574,14 +1678,14 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { void AnimationPlayerEditor::_start_onion_skinning() { // FIXME: Using "process_frame" makes onion layers update one frame behind the current. - if (!get_tree()->is_connected("process_frame", callable_mp(this, &AnimationPlayerEditor::_prepare_onion_layers_1_deferred))) { - get_tree()->connect("process_frame", callable_mp(this, &AnimationPlayerEditor::_prepare_onion_layers_1_deferred)); + if (!get_tree()->is_connected(SNAME("process_frame"), callable_mp(this, &AnimationPlayerEditor::_prepare_onion_layers_1_deferred))) { + get_tree()->connect(SNAME("process_frame"), callable_mp(this, &AnimationPlayerEditor::_prepare_onion_layers_1_deferred)); } } void AnimationPlayerEditor::_stop_onion_skinning() { - if (get_tree()->is_connected("process_frame", callable_mp(this, &AnimationPlayerEditor::_prepare_onion_layers_1_deferred))) { - get_tree()->disconnect("process_frame", callable_mp(this, &AnimationPlayerEditor::_prepare_onion_layers_1_deferred)); + if (get_tree()->is_connected(SNAME("process_frame"), callable_mp(this, &AnimationPlayerEditor::_prepare_onion_layers_1_deferred))) { + get_tree()->disconnect(SNAME("process_frame"), callable_mp(this, &AnimationPlayerEditor::_prepare_onion_layers_1_deferred)); _free_onion_layers(); @@ -1595,6 +1699,21 @@ void AnimationPlayerEditor::_pin_pressed() { SceneTreeDock::get_singleton()->get_tree_editor()->update_tree(); } +AnimationMixer *AnimationPlayerEditor::fetch_mixer_for_library() const { + if (!original_node) { + return nullptr; + } + // Does AnimationTree have AnimationPlayer? + if (original_node->is_class("AnimationTree")) { + AnimationTree *src_tree = Object::cast_to(original_node); + Node *src_player = src_tree->get_node_or_null(src_tree->get_animation_player()); + if (src_player) { + return Object::cast_to(src_player); + } + } + return original_node; +} + bool AnimationPlayerEditor::_validate_tracks(const Ref p_anim) { bool is_valid = true; if (!p_anim.is_valid()) { @@ -1668,6 +1787,10 @@ AnimationPlayer *AnimationPlayerEditor::get_player() const { return player; } +AnimationMixer *AnimationPlayerEditor::get_editing_node() const { + return original_node; +} + AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plugin) { plugin = p_plugin; singleton = this; @@ -1724,7 +1847,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug delete_dialog = memnew(ConfirmationDialog); add_child(delete_dialog); - delete_dialog->connect("confirmed", callable_mp(this, &AnimationPlayerEditor::_animation_remove_confirmed)); + delete_dialog->connect(SNAME("confirmed"), callable_mp(this, &AnimationPlayerEditor::_animation_remove_confirmed)); tool_anim = memnew(MenuButton); tool_anim->set_shortcut_context(this); @@ -1769,7 +1892,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug onion_toggle->set_theme_type_variation("FlatButton"); onion_toggle->set_toggle_mode(true); onion_toggle->set_tooltip_text(TTR("Enable Onion Skinning")); - onion_toggle->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_onion_skinning_menu).bind(ONION_SKINNING_ENABLE)); + onion_toggle->connect(SNAME("pressed"), callable_mp(this, &AnimationPlayerEditor::_onion_skinning_menu).bind(ONION_SKINNING_ENABLE)); hb->add_child(onion_toggle); onion_skinning = memnew(MenuButton); @@ -1808,7 +1931,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug pin->set_toggle_mode(true); pin->set_tooltip_text(TTR("Pin AnimationPlayer")); hb->add_child(pin); - pin->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_pin_pressed)); + pin->connect(SNAME("pressed"), callable_mp(this, &AnimationPlayerEditor::_pin_pressed)); file = memnew(EditorFileDialog); add_child(file); @@ -1838,7 +1961,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug error_dialog->set_title(TTR("Error!")); add_child(error_dialog); - name_dialog->connect("confirmed", callable_mp(this, &AnimationPlayerEditor::_animation_name_edited)); + name_dialog->connect(SNAME("confirmed"), callable_mp(this, &AnimationPlayerEditor::_animation_name_edited)); blend_editor.dialog = memnew(AcceptDialog); add_child(blend_editor.dialog); @@ -1855,20 +1978,20 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug blend_editor.dialog->set_title(TTR("Cross-Animation Blend Times")); updating_blends = false; - blend_editor.tree->connect("item_edited", callable_mp(this, &AnimationPlayerEditor::_blend_edited)); + blend_editor.tree->connect(SNAME("item_edited"), callable_mp(this, &AnimationPlayerEditor::_blend_edited)); - autoplay->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_autoplay_pressed)); + autoplay->connect(SNAME("pressed"), callable_mp(this, &AnimationPlayerEditor::_autoplay_pressed)); autoplay->set_toggle_mode(true); - play->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_play_pressed)); - play_from->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_play_from_pressed)); - play_bw->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_play_bw_pressed)); - play_bw_from->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_play_bw_from_pressed)); - stop->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_stop_pressed)); + play->connect(SNAME("pressed"), callable_mp(this, &AnimationPlayerEditor::_play_pressed)); + play_from->connect(SNAME("pressed"), callable_mp(this, &AnimationPlayerEditor::_play_from_pressed)); + play_bw->connect(SNAME("pressed"), callable_mp(this, &AnimationPlayerEditor::_play_bw_pressed)); + play_bw_from->connect(SNAME("pressed"), callable_mp(this, &AnimationPlayerEditor::_play_bw_from_pressed)); + stop->connect(SNAME("pressed"), callable_mp(this, &AnimationPlayerEditor::_stop_pressed)); - animation->connect("item_selected", callable_mp(this, &AnimationPlayerEditor::_animation_selected)); + animation->connect(SNAME("item_selected"), callable_mp(this, &AnimationPlayerEditor::_animation_selected)); - frame->connect("value_changed", callable_mp(this, &AnimationPlayerEditor::_seek_value_changed).bind(true, false)); - scale->connect("text_submitted", callable_mp(this, &AnimationPlayerEditor::_scale_changed)); + frame->connect(SNAME("value_changed"), callable_mp(this, &AnimationPlayerEditor::_seek_value_changed).bind(true, false)); + scale->connect(SNAME("text_submitted"), callable_mp(this, &AnimationPlayerEditor::_scale_changed)); last_active = false; timeline_position = 0; @@ -1877,18 +2000,18 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug add_child(track_editor); track_editor->set_v_size_flags(SIZE_EXPAND_FILL); - track_editor->connect("timeline_changed", callable_mp(this, &AnimationPlayerEditor::_animation_key_editor_seek)); - track_editor->connect("animation_len_changed", callable_mp(this, &AnimationPlayerEditor::_animation_key_editor_anim_len_changed)); + track_editor->connect(SNAME("timeline_changed"), callable_mp(this, &AnimationPlayerEditor::_animation_key_editor_seek)); + track_editor->connect(SNAME("animation_len_changed"), callable_mp(this, &AnimationPlayerEditor::_animation_key_editor_anim_len_changed)); _update_player(); library_editor = memnew(AnimationLibraryEditor); add_child(library_editor); - library_editor->connect("update_editor", callable_mp(this, &AnimationPlayerEditor::_animation_player_changed)); + library_editor->connect(SNAME("update_editor"), callable_mp(this, &AnimationPlayerEditor::_animation_player_changed)); // Onion skinning. - track_editor->connect("visibility_changed", callable_mp(this, &AnimationPlayerEditor::_editor_visibility_changed)); + track_editor->connect(SNAME("visibility_changed"), callable_mp(this, &AnimationPlayerEditor::_editor_visibility_changed)); onion.enabled = false; onion.past = true; @@ -1943,10 +2066,10 @@ AnimationPlayerEditor::~AnimationPlayerEditor() { void AnimationPlayerEditorPlugin::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - Node3DEditor::get_singleton()->connect("transform_key_request", callable_mp(this, &AnimationPlayerEditorPlugin::_transform_key_request)); - InspectorDock::get_inspector_singleton()->connect("property_keyed", callable_mp(this, &AnimationPlayerEditorPlugin::_property_keyed)); - anim_editor->get_track_editor()->connect("keying_changed", callable_mp(this, &AnimationPlayerEditorPlugin::_update_keying)); - InspectorDock::get_inspector_singleton()->connect("edited_object_changed", callable_mp(anim_editor->get_track_editor(), &AnimationTrackEditor::update_keying)); + Node3DEditor::get_singleton()->connect(SNAME("transform_key_request"), callable_mp(this, &AnimationPlayerEditorPlugin::_transform_key_request)); + InspectorDock::get_inspector_singleton()->connect(SNAME("property_keyed"), callable_mp(this, &AnimationPlayerEditorPlugin::_property_keyed)); + anim_editor->get_track_editor()->connect(SNAME("keying_changed"), callable_mp(this, &AnimationPlayerEditorPlugin::_update_keying)); + InspectorDock::get_inspector_singleton()->connect(SNAME("edited_object_changed"), callable_mp(anim_editor->get_track_editor(), &AnimationTrackEditor::update_keying)); set_force_draw_over_forwarding_enabled(); } break; } @@ -1979,14 +2102,88 @@ void AnimationPlayerEditorPlugin::_update_keying() { } void AnimationPlayerEditorPlugin::edit(Object *p_object) { + if (player && anim_editor && anim_editor->is_pinned()) { + return; // Ignore, pinned. + } + + player = nullptr; if (!p_object) { return; } - anim_editor->edit(Object::cast_to(p_object)); + last_mixer = p_object->get_instance_id(); + + AnimationMixer *src_node = Object::cast_to(p_object); + bool is_dummy = false; + if (!p_object->is_class("AnimationPlayer")) { + // If it needs dummy AnimationPlayer, assign original AnimationMixer to LibraryEditor. + _update_dummy_player(src_node); + + is_dummy = true; + + if (!src_node->is_connected(SNAME("mixer_updated"), callable_mp(this, &AnimationPlayerEditorPlugin::_update_dummy_player))) { + src_node->connect(SNAME("mixer_updated"), callable_mp(this, &AnimationPlayerEditorPlugin::_update_dummy_player).bind(src_node), CONNECT_DEFERRED); + } + if (!src_node->is_connected(SNAME("animation_libraries_updated"), callable_mp(this, &AnimationPlayerEditorPlugin::_update_dummy_player))) { + src_node->connect(SNAME("animation_libraries_updated"), callable_mp(this, &AnimationPlayerEditorPlugin::_update_dummy_player).bind(src_node), CONNECT_DEFERRED); + } + } else { + _clear_dummy_player(); + player = Object::cast_to(p_object); + } + player->set_dummy(is_dummy); + + anim_editor->edit(src_node, player, is_dummy); +} + +void AnimationPlayerEditorPlugin::_clear_dummy_player() { + if (!dummy_player) { + return; + } + Node *parent = dummy_player->get_parent(); + if (parent) { + parent->call_deferred("remove_child", dummy_player); + } + dummy_player->queue_free(); + dummy_player = nullptr; +} + +void AnimationPlayerEditorPlugin::_update_dummy_player(AnimationMixer *p_mixer) { + // Check current editing object. + if (p_mixer->get_instance_id() != last_mixer && p_mixer->is_connected(SNAME("mixer_updated"), callable_mp(this, &AnimationPlayerEditorPlugin::_update_dummy_player))) { + p_mixer->disconnect(SNAME("mixer_updated"), callable_mp(this, &AnimationPlayerEditorPlugin::_update_dummy_player)); + return; + } + + // Add dummy player to scene. + if (!dummy_player) { + Node *parent = p_mixer->get_parent(); + ERR_FAIL_NULL(parent); + dummy_player = memnew(AnimationPlayer); + parent->add_child(dummy_player); + } + player = dummy_player; + + // Convert AnimationTree (AnimationMixer) to AnimationPlayer. + AnimationMixer *default_node = memnew(AnimationMixer); + List pinfo; + default_node->get_property_list(&pinfo); + for (const PropertyInfo &E : pinfo) { + if (!(E.usage & PROPERTY_USAGE_STORAGE)) { + continue; + } + if (E.name != "script" && E.name != "active" && E.name != "deterministic" && E.name != "root_motion_track") { + dummy_player->set(E.name, p_mixer->get(E.name)); + } + } + memdelete(default_node); + + if (anim_editor) { + anim_editor->_update_player(); + } } bool AnimationPlayerEditorPlugin::handles(Object *p_object) const { - return p_object->is_class("AnimationPlayer"); + return p_object->is_class("AnimationPlayer") || p_object->is_class("AnimationTree") || p_object->is_class("AnimationMixer"); } void AnimationPlayerEditorPlugin::make_visible(bool p_visible) { @@ -2003,6 +2200,12 @@ AnimationPlayerEditorPlugin::AnimationPlayerEditorPlugin() { } AnimationPlayerEditorPlugin::~AnimationPlayerEditorPlugin() { + if (dummy_player) { + memdelete(dummy_player); + } + if (player) { + memdelete(player); + } } // AnimationTrackKeyEditEditorPlugin diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h index 8c46b5c36e..4763a008fe 100644 --- a/editor/plugins/animation_player_editor_plugin.h +++ b/editor/plugins/animation_player_editor_plugin.h @@ -47,8 +47,12 @@ class ImageTexture; class AnimationPlayerEditor : public VBoxContainer { GDCLASS(AnimationPlayerEditor, VBoxContainer); + friend AnimationPlayerEditorPlugin; + AnimationPlayerEditorPlugin *plugin = nullptr; - AnimationPlayer *player = nullptr; + AnimationMixer *original_node = nullptr; // For pinned mark in SceneTree. + AnimationPlayer *player = nullptr; // For AnimationPlayerEditor, could be dummy. + bool is_dummy = false; enum { TOOL_NEW_ANIM, @@ -189,6 +193,7 @@ class AnimationPlayerEditor : public VBoxContainer { void _blend_editor_next_changed(const int p_idx); void _list_changed(); + void _current_animation_changed(const String &p_name); void _update_animation(); void _update_player(); void _update_animation_list_icons(); @@ -220,6 +225,8 @@ class AnimationPlayerEditor : public VBoxContainer { void _pin_pressed(); String _get_current() const; + void _ensure_dummy_player(); + ~AnimationPlayerEditor(); protected: @@ -228,19 +235,24 @@ protected: static void _bind_methods(); public: + AnimationMixer *get_editing_node() const; AnimationPlayer *get_player() const; + AnimationMixer *fetch_mixer_for_library() const; static AnimationPlayerEditor *get_singleton() { return singleton; } bool is_pinned() const { return pin->is_pressed(); } - void unpin() { pin->set_pressed(false); } + void unpin() { + pin->set_pressed(false); + _pin_pressed(); + } AnimationTrackEditor *get_track_editor() { return track_editor; } Dictionary get_state() const; void set_state(const Dictionary &p_state); void ensure_visibility(); - void edit(AnimationPlayer *p_player); + void edit(AnimationMixer *p_node, AnimationPlayer *p_player, bool p_is_dummy); void forward_force_draw_over_viewport(Control *p_overlay); AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plugin); @@ -249,7 +261,15 @@ public: class AnimationPlayerEditorPlugin : public EditorPlugin { GDCLASS(AnimationPlayerEditorPlugin, EditorPlugin); + friend AnimationPlayerEditor; + AnimationPlayerEditor *anim_editor = nullptr; + AnimationPlayer *player = nullptr; + AnimationPlayer *dummy_player = nullptr; + ObjectID last_mixer; + + void _update_dummy_player(AnimationMixer *p_mixer); + void _clear_dummy_player(); protected: void _notification(int p_what); diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index f25f6ccd04..746a901a0a 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -92,7 +92,7 @@ String AnimationNodeStateMachineEditor::_get_root_playback_path(String &r_node_d if (edited_path.size()) { while (!is_playable_anodesm_found) { base_path = String("/").join(edited_path); - Ref anodesm = !edited_path.size() ? tree->get_tree_root() : tree->get_tree_root()->find_node_by_path(base_path); + Ref anodesm = !edited_path.size() ? Ref(tree->get_root_animation_node().ptr()) : tree->get_root_animation_node()->find_node_by_path(base_path); if (!anodesm.is_valid()) { break; } else { @@ -562,13 +562,7 @@ void AnimationNodeStateMachineEditor::_open_menu(const Vector2 &p_position) { animations_to_add.clear(); List animation_names; - if (tree->has_node(tree->get_animation_player())) { - AnimationPlayer *ap = Object::cast_to(tree->get_node(tree->get_animation_player())); - if (ap) { - ap->get_animation_list(&animation_names); - } - } - + tree->get_animation_list(&animation_names); menu->add_submenu_item(TTR("Add Animation"), "animations"); if (animation_names.is_empty()) { menu->set_item_disabled(menu->get_item_idx_from_text(TTR("Add Animation")), true); diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp index 7b5f8aa7f7..1c642f909a 100644 --- a/editor/plugins/animation_tree_editor_plugin.cpp +++ b/editor/plugins/animation_tree_editor_plugin.cpp @@ -50,16 +50,16 @@ #include "scene/scene_string_names.h" void AnimationTreeEditor::edit(AnimationTree *p_tree) { - if (p_tree && !p_tree->is_connected("animation_player_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed))) { - p_tree->connect("animation_player_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed), CONNECT_DEFERRED); + if (p_tree && !p_tree->is_connected("animation_list_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed))) { + p_tree->connect("animation_list_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed), CONNECT_DEFERRED); } if (tree == p_tree) { return; } - if (tree && tree->is_connected("animation_player_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed))) { - tree->disconnect("animation_player_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed)); + if (tree && tree->is_connected("animation_list_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed))) { + tree->disconnect("animation_list_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed)); } tree = p_tree; @@ -122,7 +122,7 @@ void AnimationTreeEditor::_update_path() { void AnimationTreeEditor::edit_path(const Vector &p_path) { button_path.clear(); - Ref node = tree->get_tree_root(); + Ref node = tree->get_root_animation_node(); if (node.is_valid()) { current_root = node->get_instance_id(); @@ -185,8 +185,8 @@ void AnimationTreeEditor::_notification(int p_what) { } break; case NOTIFICATION_PROCESS: { ObjectID root; - if (tree && tree->get_tree_root().is_valid()) { - root = tree->get_tree_root()->get_instance_id(); + if (tree && tree->get_root_animation_node().is_valid()) { + root = tree->get_root_animation_node()->get_instance_id(); } if (root != current_root) { @@ -247,18 +247,12 @@ Vector AnimationTreeEditor::get_animation_list() { } AnimationTree *tree = singleton->tree; - if (!tree || !tree->has_node(tree->get_animation_player())) { - return Vector(); - } - - AnimationPlayer *ap = Object::cast_to(tree->get_node(tree->get_animation_player())); - - if (!ap) { + if (!tree) { return Vector(); } List anims; - ap->get_animation_list(&anims); + tree->get_animation_list(&anims); Vector ret; for (const StringName &E : anims) { ret.push_back(E); diff --git a/editor/plugins/root_motion_editor_plugin.cpp b/editor/plugins/root_motion_editor_plugin.cpp index 10b0b214ae..bc6507155a 100644 --- a/editor/plugins/root_motion_editor_plugin.cpp +++ b/editor/plugins/root_motion_editor_plugin.cpp @@ -29,9 +29,10 @@ /**************************************************************************/ #include "root_motion_editor_plugin.h" + #include "editor/editor_node.h" -#include "scene/animation/animation_player.h" -#include "scene/animation/animation_tree.h" +#include "editor/editor_scale.h" +#include "scene/animation/animation_mixer.h" #include "scene/gui/button.h" #include "scene/gui/dialogs.h" #include "scene/gui/tree.h" @@ -50,31 +51,26 @@ void EditorPropertyRootMotion::_confirmed() { } void EditorPropertyRootMotion::_node_assign() { - AnimationTree *atree = Object::cast_to(get_edited_object()); - if (!atree->has_node(atree->get_animation_player())) { - EditorNode::get_singleton()->show_warning(TTR("AnimationTree has no path set to an AnimationPlayer")); - return; - } - AnimationPlayer *player = Object::cast_to(atree->get_node(atree->get_animation_player())); - if (!player) { - EditorNode::get_singleton()->show_warning(TTR("Path to AnimationPlayer is invalid")); + AnimationMixer *mixer = Object::cast_to(get_edited_object()); + if (!mixer) { + EditorNode::get_singleton()->show_warning(TTR("Path to AnimationMixer is invalid")); return; } - Node *base = player->get_node(player->get_root()); + Node *base = mixer->get_node(mixer->get_root_node()); if (!base) { - EditorNode::get_singleton()->show_warning(TTR("Animation player has no valid root node path, so unable to retrieve track names.")); + EditorNode::get_singleton()->show_warning(TTR("AnimationMixer has no valid root node path, so unable to retrieve track names.")); return; } HashSet paths; { List animations; - player->get_animation_list(&animations); + mixer->get_animation_list(&animations); for (const StringName &E : animations) { - Ref anim = player->get_animation(E); + Ref anim = mixer->get_animation(E); for (int i = 0; i < anim->get_track_count(); i++) { String pathname = anim->track_get_path(i).get_concatenated_names(); if (!paths.has(pathname)) { @@ -160,7 +156,7 @@ void EditorPropertyRootMotion::_node_assign() { } filters->ensure_cursor_is_visible(); - filter_dialog->popup_centered_ratio(); + filter_dialog->popup_centered(Size2(500, 500) * EDSCALE); } void EditorPropertyRootMotion::_node_clear() { @@ -232,7 +228,7 @@ bool EditorInspectorRootMotionPlugin::can_handle(Object *p_object) { } bool EditorInspectorRootMotionPlugin::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField p_usage, const bool p_wide) { - if (p_path == "root_motion_track" && p_object->is_class("AnimationTree") && p_type == Variant::NODE_PATH) { + if (p_path == "root_motion_track" && p_object->is_class("AnimationMixer") && p_type == Variant::NODE_PATH) { EditorPropertyRootMotion *editor = memnew(EditorPropertyRootMotion); add_property_editor(p_path, editor); return true; diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index d7c6cb04a4..a83dedad6d 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -1548,7 +1548,7 @@ void SceneTreeDock::_fill_path_renames(Vector base_path, Vector &p_to_delete) const { AnimationPlayer *ap = Object::cast_to(p_node); if (ap) { - Node *root = ap->get_node(ap->get_root()); + Node *root = ap->get_node(ap->get_root_node()); if (root && !p_to_delete.find(root)) { List anims; ap->get_animation_list(&anims); @@ -1735,7 +1735,7 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap AnimationPlayer *ap = Object::cast_to(p_base); List anims; ap->get_animation_list(&anims); - Node *root = ap->get_node(ap->get_root()); + Node *root = ap->get_node(ap->get_root_node()); if (root) { HashMap::Iterator found_root_path = p_renames->find(root); -- cgit v1.2.3