diff --git a/doc/classes/AnimationMixer.xml b/doc/classes/AnimationMixer.xml
index 4a489a3ef23..31308c4e20e 100644
--- a/doc/classes/AnimationMixer.xml
+++ b/doc/classes/AnimationMixer.xml
@@ -15,10 +15,10 @@
-
-
+
+
- A virtual function for processing after key getting during playback.
+ A virtual function for processing after getting a key during playback.
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index 5011c5cf182..5ffb89ac659 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -41,6 +41,7 @@
#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
#include "editor/gui/editor_file_dialog.h"
+#include "scene/3d/skeleton_3d.h"
#include "scene/animation/animation_player.h"
#include "scene/gui/check_box.h"
#include "scene/gui/menu_button.h"
diff --git a/editor/plugins/root_motion_editor_plugin.cpp b/editor/plugins/root_motion_editor_plugin.cpp
index bc6507155ad..b54a2f717d5 100644
--- a/editor/plugins/root_motion_editor_plugin.cpp
+++ b/editor/plugins/root_motion_editor_plugin.cpp
@@ -32,6 +32,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "scene/3d/skeleton_3d.h"
#include "scene/animation/animation_mixer.h"
#include "scene/gui/button.h"
#include "scene/gui/dialogs.h"
diff --git a/misc/extension_api_validation/4.2-stable.expected b/misc/extension_api_validation/4.2-stable.expected
index 70358c683ff..a8b3af78919 100644
--- a/misc/extension_api_validation/4.2-stable.expected
+++ b/misc/extension_api_validation/4.2-stable.expected
@@ -21,3 +21,10 @@ GH-85393
Validate extension JSON: Error: Field 'classes/PhysicsShapeQueryParameters3D/properties/motion': type changed value in new API, from "Vector2" to "Vector3".
The type was registered wrongly, this was a bug.
+
+
+GH-86687
+--------
+Validate extension JSON: Error: Field 'classes/AnimationMixer/methods/_post_process_key_value/arguments/3': type changed value in new API, from "Object" to "int".
+
+Exposing the pointer was dangerous and it must be changed to avoid crash. Compatibility methods registered.
diff --git a/modules/gltf/extensions/gltf_document_extension.h b/modules/gltf/extensions/gltf_document_extension.h
index 512b7aba91d..761dff725c2 100644
--- a/modules/gltf/extensions/gltf_document_extension.h
+++ b/modules/gltf/extensions/gltf_document_extension.h
@@ -33,6 +33,8 @@
#include "../gltf_state.h"
+#include "scene/3d/node_3d.h"
+
class GLTFDocumentExtension : public Resource {
GDCLASS(GLTFDocumentExtension, Resource);
diff --git a/modules/gltf/structures/gltf_skin.h b/modules/gltf/structures/gltf_skin.h
index 164cabfe128..cd5f2d9ca25 100644
--- a/modules/gltf/structures/gltf_skin.h
+++ b/modules/gltf/structures/gltf_skin.h
@@ -34,6 +34,7 @@
#include "../gltf_defines.h"
#include "core/io/resource.h"
+#include "scene/resources/skin.h"
template
class TypedArray;
diff --git a/scene/animation/animation_mixer.compat.inc b/scene/animation/animation_mixer.compat.inc
new file mode 100644
index 00000000000..09c7d7a977b
--- /dev/null
+++ b/scene/animation/animation_mixer.compat.inc
@@ -0,0 +1,44 @@
+/**************************************************************************/
+/* animation_mixer.compat.inc */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef DISABLE_DEPRECATED
+
+Variant AnimationMixer::_post_process_key_value_bind_compat_86687(const Ref &p_anim, int p_track, Variant p_value, Object *p_object, int p_object_idx) {
+ if (!p_object) {
+ return Variant();
+ }
+ return _post_process_key_value(p_anim, p_track, p_value, p_object->get_instance_id(), p_object_idx);
+}
+
+void AnimationMixer::_bind_compatibility_methods() {
+ ClassDB::bind_compatibility_method(D_METHOD("_post_process_key_value_bind_compat", "animation", "track", "value", "object", "object_idx"), &AnimationMixer::_post_process_key_value_bind_compat_86687);
+}
+
+#endif // DISABLE_DEPRECATED
diff --git a/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp
index 441d5878ae3..faf11531780 100644
--- a/scene/animation/animation_mixer.cpp
+++ b/scene/animation/animation_mixer.cpp
@@ -29,8 +29,12 @@
/**************************************************************************/
#include "animation_mixer.h"
+#include "animation_mixer.compat.inc"
#include "core/config/engine.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/3d/node_3d.h"
+#include "scene/3d/skeleton_3d.h"
#include "scene/animation/animation_player.h"
#include "scene/resources/animation.h"
#include "scene/scene_string_names.h"
@@ -543,7 +547,7 @@ void AnimationMixer::_clear_caches() {
_init_root_motion_cache();
_clear_audio_streams();
_clear_playing_caches();
- for (KeyValue &K : track_cache) {
+ for (KeyValue &K : track_cache) {
memdelete(K.value);
}
track_cache.clear();
@@ -562,8 +566,9 @@ void AnimationMixer::_clear_audio_streams() {
void AnimationMixer::_clear_playing_caches() {
for (const TrackCache *E : playing_caches) {
- if (ObjectDB::get_instance(E->object_id)) {
- E->object->call(SNAME("stop"), true);
+ Object *t_obj = ObjectDB::get_instance(E->object_id);
+ if (t_obj) {
+ t_obj->call(SNAME("stop"), true);
}
}
playing_caches.clear();
@@ -606,23 +611,20 @@ bool AnimationMixer::_update_caches() {
Ref anim = get_animation(E);
for (int i = 0; i < anim->get_track_count(); i++) {
NodePath path = anim->track_get_path(i);
- Animation::TrackType track_type = anim->track_get_type(i);
-
- Animation::TrackType track_cache_type = track_type;
- if (track_cache_type == Animation::TYPE_POSITION_3D || track_cache_type == Animation::TYPE_ROTATION_3D || track_cache_type == Animation::TYPE_SCALE_3D) {
- track_cache_type = Animation::TYPE_POSITION_3D; // Reference them as position3D tracks, even if they modify rotation or scale.
- }
+ Animation::TypeHash thash = anim->track_get_type_hash(i);
+ Animation::TrackType track_src_type = anim->track_get_type(i);
+ Animation::TrackType track_cache_type = Animation::get_cache_type(track_src_type);
TrackCache *track = nullptr;
- if (track_cache.has(path)) {
- track = track_cache.get(path);
+ if (track_cache.has(thash)) {
+ track = track_cache.get(thash);
}
// If not valid, delete track.
if (track && (track->type != track_cache_type || ObjectDB::get_instance(track->object_id) == nullptr)) {
playing_caches.erase(track);
memdelete(track);
- track_cache.erase(path);
+ track_cache.erase(thash);
track = nullptr;
}
@@ -636,7 +638,8 @@ bool AnimationMixer::_update_caches() {
continue;
}
- switch (track_type) {
+ switch (track_src_type) {
+ case Animation::TYPE_BEZIER:
case Animation::TYPE_VALUE: {
// If a value track without a key is cached first, the initial value cannot be determined.
// It is a corner case, but which may cause problems with blending.
@@ -645,16 +648,20 @@ bool AnimationMixer::_update_caches() {
TrackCacheValue *track_value = memnew(TrackCacheValue);
if (resource.is_valid()) {
- track_value->object = resource.ptr();
+ track_value->object_id = resource->get_instance_id();
} else {
- track_value->object = child;
+ track_value->object_id = child->get_instance_id();
}
- track_value->is_continuous = anim->value_track_get_update_mode(i) != Animation::UPDATE_DISCRETE;
- track_value->is_using_angle = anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE;
+ if (track_src_type == Animation::TYPE_VALUE) {
+ track_value->is_continuous = anim->value_track_get_update_mode(i) != Animation::UPDATE_DISCRETE;
+ track_value->is_using_angle = anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE;
+ } else {
+ track_value->is_continuous = true;
+ track_value->is_using_angle = false;
+ }
track_value->subpath = leftover_path;
- track_value->object_id = track_value->object->get_instance_id();
track = track_value;
@@ -663,9 +670,9 @@ bool AnimationMixer::_update_caches() {
// If there is a Reset Animation, it takes precedence by overwriting.
if (has_reset_anim) {
- int rt = reset_anim->find_track(path, track_type);
+ int rt = reset_anim->find_track(path, track_src_type);
if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) {
- track_value->init_value = reset_anim->track_get_key_value(rt, 0);
+ track_value->init_value = track_src_type == Animation::TYPE_VALUE ? reset_anim->track_get_key_value(rt, 0) : (reset_anim->track_get_key_value(rt, 0).operator Array())[0];
}
}
@@ -684,14 +691,12 @@ bool AnimationMixer::_update_caches() {
TrackCacheTransform *track_xform = memnew(TrackCacheTransform);
track_xform->type = Animation::TYPE_POSITION_3D;
- track_xform->node_3d = node_3d;
- track_xform->skeleton = nullptr;
track_xform->bone_idx = -1;
bool has_rest = false;
- if (path.get_subname_count() == 1 && Object::cast_to(node_3d)) {
- Skeleton3D *sk = Object::cast_to(node_3d);
- track_xform->skeleton = sk;
+ Skeleton3D *sk = Object::cast_to(node_3d);
+ if (sk && path.get_subname_count() == 1) {
+ track_xform->skeleton_id = sk->get_instance_id();
int bone_idx = sk->find_bone(path.get_subname(0));
if (bone_idx != -1) {
has_rest = true;
@@ -703,12 +708,11 @@ bool AnimationMixer::_update_caches() {
}
}
- track_xform->object = node_3d;
- track_xform->object_id = track_xform->object->get_instance_id();
+ track_xform->object_id = node_3d->get_instance_id();
track = track_xform;
- switch (track_type) {
+ switch (track_src_type) {
case Animation::TYPE_POSITION_3D: {
track_xform->loc_used = true;
} break;
@@ -724,9 +728,9 @@ bool AnimationMixer::_update_caches() {
// For non Skeleton3D bone animation.
if (has_reset_anim && !has_rest) {
- int rt = reset_anim->find_track(path, track_type);
+ int rt = reset_anim->find_track(path, track_src_type);
if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) {
- switch (track_type) {
+ switch (track_src_type) {
case Animation::TYPE_POSITION_3D: {
track_xform->init_loc = reset_anim->track_get_key_value(rt, 0);
} break;
@@ -765,15 +769,12 @@ bool AnimationMixer::_update_caches() {
TrackCacheBlendShape *track_bshape = memnew(TrackCacheBlendShape);
- track_bshape->mesh_3d = mesh_3d;
track_bshape->shape_index = blend_shape_idx;
-
- track_bshape->object = mesh_3d;
track_bshape->object_id = mesh_3d->get_instance_id();
track = track_bshape;
if (has_reset_anim) {
- int rt = reset_anim->find_track(path, track_type);
+ int rt = reset_anim->find_track(path, track_src_type);
if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) {
track_bshape->init_value = reset_anim->track_get_key_value(rt, 0);
}
@@ -784,43 +785,18 @@ bool AnimationMixer::_update_caches() {
TrackCacheMethod *track_method = memnew(TrackCacheMethod);
if (resource.is_valid()) {
- track_method->object = resource.ptr();
+ track_method->object_id = resource->get_instance_id();
} else {
- track_method->object = child;
+ track_method->object_id = child->get_instance_id();
}
- track_method->object_id = track_method->object->get_instance_id();
-
track = track_method;
- } break;
- case Animation::TYPE_BEZIER: {
- TrackCacheBezier *track_bezier = memnew(TrackCacheBezier);
-
- if (resource.is_valid()) {
- track_bezier->object = resource.ptr();
- } else {
- track_bezier->object = child;
- }
-
- track_bezier->subpath = leftover_path;
- track_bezier->object_id = track_bezier->object->get_instance_id();
-
- track = track_bezier;
-
- if (has_reset_anim) {
- int rt = reset_anim->find_track(path, track_type);
- if (rt >= 0 && reset_anim->track_get_key_count(rt) > 0) {
- track_bezier->init_value = (reset_anim->track_get_key_value(rt, 0).operator Array())[0];
- }
- }
-
} break;
case Animation::TYPE_AUDIO: {
TrackCacheAudio *track_audio = memnew(TrackCacheAudio);
- track_audio->object = child;
- track_audio->object_id = track_audio->object->get_instance_id();
+ track_audio->object_id = child->get_instance_id();
track_audio->audio_stream.instantiate();
track_audio->audio_stream->set_polyphony(audio_max_polyphony);
@@ -830,8 +806,7 @@ bool AnimationMixer::_update_caches() {
case Animation::TYPE_ANIMATION: {
TrackCacheAnimation *track_animation = memnew(TrackCacheAnimation);
- track_animation->object = child;
- track_animation->object_id = track_animation->object->get_instance_id();
+ track_animation->object_id = child->get_instance_id();
track = track_animation;
@@ -841,8 +816,8 @@ bool AnimationMixer::_update_caches() {
continue;
}
}
-
- track_cache[path] = track;
+ track->path = path;
+ track_cache[thash] = track;
} else if (track_cache_type == Animation::TYPE_POSITION_3D) {
TrackCacheTransform *track_xform = static_cast(track);
if (track->setup_pass != setup_pass) {
@@ -850,7 +825,7 @@ bool AnimationMixer::_update_caches() {
track_xform->rot_used = false;
track_xform->scale_used = false;
}
- switch (track_type) {
+ switch (track_src_type) {
case Animation::TYPE_POSITION_3D: {
track_xform->loc_used = true;
} break;
@@ -868,8 +843,13 @@ bool AnimationMixer::_update_caches() {
TrackCacheValue *track_value = static_cast(track);
bool was_continuous = track_value->is_continuous;
bool was_using_angle = track_value->is_using_angle;
- track_value->is_continuous |= anim->value_track_get_update_mode(i) != Animation::UPDATE_DISCRETE;
- track_value->is_using_angle |= anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE;
+
+ if (track_src_type == Animation::TYPE_VALUE) {
+ track_value->is_continuous |= anim->value_track_get_update_mode(i) != Animation::UPDATE_DISCRETE;
+ track_value->is_using_angle |= anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE;
+ } else {
+ track_value->is_continuous |= true;
+ }
// TODO: Currently, misc type cannot be blended.
// In the future, it should have a separate blend weight, just as bool is converted to 0 and 1.
@@ -898,27 +878,26 @@ bool AnimationMixer::_update_caches() {
}
}
- List to_delete;
+ List to_delete;
- for (const KeyValue &K : track_cache) {
- TrackCache *tc = track_cache[K.key];
- if (tc->setup_pass != setup_pass) {
+ for (const KeyValue &K : track_cache) {
+ if (K.value->setup_pass != setup_pass) {
to_delete.push_back(K.key);
}
}
while (to_delete.front()) {
- NodePath np = to_delete.front()->get();
- memdelete(track_cache[np]);
- track_cache.erase(np);
+ Animation::TypeHash thash = to_delete.front()->get();
+ memdelete(track_cache[thash]);
+ track_cache.erase(thash);
to_delete.pop_front();
}
track_map.clear();
int idx = 0;
- for (const KeyValue &K : track_cache) {
- track_map[K.key] = idx;
+ for (const KeyValue &K : track_cache) {
+ track_map[K.value->path] = idx;
idx++;
}
@@ -944,19 +923,28 @@ void AnimationMixer::_process_animation(double p_delta, bool p_update_only) {
clear_animation_instances();
}
-Variant AnimationMixer::post_process_key_value(const Ref &p_anim, int p_track, Variant p_value, const Object *p_object, int p_object_idx) {
+Variant AnimationMixer::post_process_key_value(const Ref &p_anim, int p_track, Variant p_value, ObjectID p_object_id, int p_object_sub_idx) {
Variant res;
- if (GDVIRTUAL_CALL(_post_process_key_value, p_anim, p_track, p_value, const_cast