summaryrefslogtreecommitdiffstats
path: root/editor
diff options
context:
space:
mode:
authorSilc Lizard (Tokage) Renew <61938263+TokageItLab@users.noreply.github.com>2023-07-21 00:34:06 +0900
committerSilc Lizard (Tokage) Renew <61938263+TokageItLab@users.noreply.github.com>2023-09-29 08:23:57 +0900
commit1b95827d3ef244de322b0c16deb49fefe48ed1a1 (patch)
treedb06582520fc1e0978ac0e0908b44cd6b4b9baa6 /editor
parent545d1c0adbf340310e1531710eb31bd5267704d5 (diff)
downloadredot-engine-1b95827d3ef244de322b0c16deb49fefe48ed1a1.tar.gz
Implement AnimationManager the base class of AnimationPlayer/Tree
Diffstat (limited to 'editor')
-rw-r--r--editor/animation_track_editor.cpp53
-rw-r--r--editor/animation_track_editor.h8
-rw-r--r--editor/editor_node.cpp25
-rw-r--r--editor/gui/scene_tree_editor.cpp6
-rw-r--r--editor/icons/AnimationMixer.svg1
-rw-r--r--editor/import/post_import_plugin_skeleton_renamer.cpp6
-rw-r--r--editor/import/post_import_plugin_skeleton_rest_fixer.cpp10
-rw-r--r--editor/import/post_import_plugin_skeleton_track_organizer.cpp2
-rw-r--r--editor/import/resource_importer_scene.cpp2
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.cpp16
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.cpp15
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp70
-rw-r--r--editor/plugins/animation_library_editor.cpp124
-rw-r--r--editor/plugins/animation_library_editor.h8
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp349
-rw-r--r--editor/plugins/animation_player_editor_plugin.h26
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp10
-rw-r--r--editor/plugins/animation_tree_editor_plugin.cpp24
-rw-r--r--editor/plugins/root_motion_editor_plugin.cpp28
-rw-r--r--editor/scene_tree_dock.cpp4
20 files changed, 502 insertions, 285 deletions
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<InputEvent> &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<Animation> AnimationTrackEditor::_create_and_get_reset_animation() {
return player->get_animation(SceneStringNames::get_singleton()->RESET);
} else {
Ref<AnimationLibrary> 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<Animation> 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<AnimationTrackEdit *> track_edits;
Vector<AnimationTrackEditGroup *> 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<Ref<AnimatedValuesBackup>> *r_anim_backups) {
+static void _reset_animation_mixers(Node *p_node, List<Pair<AnimationMixer *, Ref<AnimatedValuesBackup>>> *r_anim_backups) {
for (int i = 0; i < p_node->get_child_count(); i++) {
- AnimationPlayer *player = Object::cast_to<AnimationPlayer>(p_node->get_child(i));
- if (player && player->is_reset_on_save_enabled() && player->can_apply_reset()) {
- Ref<AnimatedValuesBackup> old_values = player->apply_reset();
- if (old_values.is_valid()) {
- r_anim_backups->push_back(old_values);
+ AnimationMixer *mixer = Object::cast_to<AnimationMixer>(p_node->get_child(i));
+ if (mixer && mixer->is_reset_on_save_enabled() && mixer->can_apply_reset()) {
+ Ref<AnimatedValuesBackup> backup = mixer->apply_reset();
+ if (backup.is_valid()) {
+ Pair<AnimationMixer *, Ref<AnimatedValuesBackup>> 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<Ref<AnimatedValuesBackup>> anim_backups;
- _reset_animation_players(scene, &anim_backups);
+ List<Pair<AnimationMixer *, Ref<AnimatedValuesBackup>>> 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<AnimatedValuesBackup> &E : anim_backups) {
- E->restore();
+ for (Pair<AnimationMixer *, Ref<AnimatedValuesBackup>> &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 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M1 1v14h1v-2h2v2h8v-2h2v2h1V1h-1v2h-2V1H4v2H2V1zm1 4h2v2H2zm10 0h2v2h-2zM2 9h2v2H2zm10 0h2v2h-2z" fill="#919191"/></svg>
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<Skeleton3D>(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<Skeleton3D>(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<Skeleton3D>(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<Skeleton3D>(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<Skeleton3D>(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<Skeleton3D>(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<Skeleton3D>(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<int> 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<R
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(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 Ref<InputEven
menu->add_submenu_item(TTR("Add Animation"), "animations");
- if (tree->has_node(tree->get_animation_player())) {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(tree->get_node(tree->get_animation_player()));
+ List<StringName> names;
+ tree->get_animation_list(&names);
- if (ap) {
- List<StringName> 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 Ref<InputEven
ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
menu->add_submenu_item(TTR("Add Animation"), "animations");
- if (tree->has_node(tree->get_animation_player())) {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(tree->get_node(tree->get_animation_player()));
- if (ap) {
- List<StringName> 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<StringName> 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<AnimationPlayer>(tree->get_node(tree->get_animation_player()));
- if (ap) {
- List<StringName> anims;
- ap->get_animation_list(&anims);
-
- for (const StringName &F : anims) {
- mb->get_popup()->add_item(F);
- options.push_back(F);
- }
+ List<StringName> 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<AnimationNode> &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<AnimationPlayer>(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<AnimationNode> &ano
HashMap<String, RBSet<String>> types;
{
List<StringName> animation_list;
- player->get_animation_list(&animation_list);
+ tree->get_animation_list(&animation_list);
for (const StringName &E : animation_list) {
- Ref<Animation> anim = player->get_animation(E);
+ Ref<Animation> 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<AnimationPlayer>(tree->get_node(tree->get_animation_player()));
- }
-
- if (player) {
- for (const KeyValue<StringName, ProgressBar *> &E : animations) {
- Ref<AnimationNodeAnimation> an = blend_tree->get_node(E.key);
- if (an.is_valid()) {
- if (player->has_animation(an->get_animation())) {
- Ref<Animation> 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<StringName, ProgressBar *> &E : animations) {
+ Ref<AnimationNodeAnimation> an = blend_tree->get_node(E.key);
+ if (an.is_valid()) {
+ if (tree->has_animation(an->get_animation())) {
+ Ref<Animation> 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<AnimationLibrary> al = player->call("get_animation_library", adding_animation_to_library);
+ Ref<AnimationLibrary> 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<AnimationLibrary> al = player->call("get_animation_library", adding_animation_to_library);
+ Ref<AnimationLibrary> al = mixer->call("get_animation_library", adding_animation_to_library);
ERR_FAIL_COND(!al.is_valid());
Ref<Animation> 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<AnimationLibrary> al = player->call("get_animation_library", file_dialog_library);
+ Ref<AnimationLibrary> al = mixer->call("get_animation_library", file_dialog_library);
Ref<Animation> 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<StringName> libs = player->call("get_animation_library_list");
+ TypedArray<StringName> libs = mixer->call("get_animation_library_list");
for (int i = 0; i < libs.size(); i++) {
const StringName K = libs[i];
- Ref<AnimationLibrary> al2 = player->call("get_animation_library", K);
+ Ref<AnimationLibrary> 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<AnimationLibrary> al = player->call("get_animation_library", adding_animation_to_library);
+ Ref<AnimationLibrary> al = mixer->call("get_animation_library", adding_animation_to_library);
List<StringName> 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<AnimationLibrary> al = player->call("get_animation_library", file_dialog_library);
+ Ref<AnimationLibrary> 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<AnimationLibrary> al = player->call("get_animation_library", file_dialog_library);
+ Ref<AnimationLibrary> al = mixer->call("get_animation_library", file_dialog_library);
Ref<Animation> 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<AnimationLibrary> al = player->call("get_animation_library", library);
+ Ref<AnimationLibrary> 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<AnimationLibrary> al = player->call("get_animation_library", lib_name);
+ Ref<AnimationLibrary> 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<AnimationLibrary> al = player->call("get_animation_library", lib_name);
+ Ref<AnimationLibrary> al = mixer->call("get_animation_library", lib_name);
Ref<Animation> 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<StringName> libs = player->call("get_animation_library_list");
+ TypedArray<StringName> 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<AnimationLibrary> al = player->call("get_animation_library", K);
+ Ref<AnimationLibrary> 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<Animation>(), 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<AnimationPlayer>(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<AnimationPlayer>(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<AnimationTree>(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<Animation> 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<AnimatedValuesBackup> values_backup = player->backup_animated_values();
+ Ref<AnimatedValuesBackup> 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<AnimationTree>(original_node);
+ Node *src_player = src_tree->get_node_or_null(src_tree->get_animation_player());
+ if (src_player) {
+ return Object::cast_to<AnimationMixer>(src_player);
+ }
+ }
+ return original_node;
+}
+
bool AnimationPlayerEditor::_validate_tracks(const Ref<Animation> 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<AnimationPlayer>(p_object));
+ last_mixer = p_object->get_instance_id();
+
+ AnimationMixer *src_node = Object::cast_to<AnimationMixer>(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<AnimationPlayer>(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<PropertyInfo> 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<AnimationNodeStateMachine> anodesm = !edited_path.size() ? tree->get_tree_root() : tree->get_tree_root()->find_node_by_path(base_path);
+ Ref<AnimationNodeStateMachine> anodesm = !edited_path.size() ? Ref<AnimationNode>(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<StringName> animation_names;
- if (tree->has_node(tree->get_animation_player())) {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(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<String> &p_path) {
button_path.clear();
- Ref<AnimationNode> node = tree->get_tree_root();
+ Ref<AnimationNode> 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<String> AnimationTreeEditor::get_animation_list() {
}
AnimationTree *tree = singleton->tree;
- if (!tree || !tree->has_node(tree->get_animation_player())) {
- return Vector<String>();
- }
-
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(tree->get_node(tree->get_animation_player()));
-
- if (!ap) {
+ if (!tree) {
return Vector<String>();
}
List<StringName> anims;
- ap->get_animation_list(&anims);
+ tree->get_animation_list(&anims);
Vector<String> 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<AnimationTree>(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<AnimationPlayer>(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<AnimationMixer>(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<String> paths;
{
List<StringName> animations;
- player->get_animation_list(&animations);
+ mixer->get_animation_list(&animations);
for (const StringName &E : animations) {
- Ref<Animation> anim = player->get_animation(E);
+ Ref<Animation> 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<PropertyUsageFlags> 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<StringName> base_path, Vector<Stri
bool SceneTreeDock::_has_tracks_to_delete(Node *p_node, List<Node *> &p_to_delete) const {
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(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<StringName> anims;
ap->get_animation_list(&anims);
@@ -1735,7 +1735,7 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath>
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_base);
List<StringName> 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<Node *, NodePath>::Iterator found_root_path = p_renames->find(root);