From a51958a2a0620aa1a9b9a168259379511f9521ad Mon Sep 17 00:00:00 2001 From: "Silc Lizard (Tokage) Renew" <61938263+TokageItLab@users.noreply.github.com> Date: Sat, 6 Jan 2024 02:21:38 +0900 Subject: [PATCH] Remove Object pointer/solve types conflict in AnimationTrackCache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: RĂ©mi Verschelde --- doc/classes/AnimationMixer.xml | 6 +- .../animation_blend_tree_editor_plugin.cpp | 1 + editor/plugins/root_motion_editor_plugin.cpp | 1 + .../4.2-stable.expected | 7 + .../gltf/extensions/gltf_document_extension.h | 2 + modules/gltf/structures/gltf_skin.h | 1 + scene/animation/animation_mixer.compat.inc | 44 ++ scene/animation/animation_mixer.cpp | 411 +++++++++--------- scene/animation/animation_mixer.h | 54 +-- scene/resources/animation.cpp | 22 + scene/resources/animation.h | 11 +- 11 files changed, 312 insertions(+), 248 deletions(-) create mode 100644 scene/animation/animation_mixer.compat.inc 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(p_object), p_object_idx, res)) { + if (GDVIRTUAL_CALL(_post_process_key_value, p_anim, p_track, p_value, p_object_id, p_object_sub_idx, res)) { return res; } - return _post_process_key_value(p_anim, p_track, p_value, p_object, p_object_idx); + return _post_process_key_value(p_anim, p_track, p_value, p_object_id, p_object_sub_idx); } -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) { #ifndef _3D_DISABLED - if (p_object_idx >= 0 && p_anim->track_get_type(p_track) == Animation::TYPE_POSITION_3D) { - const Skeleton3D *skel = Object::cast_to(p_object); - return Vector3(p_value) * skel->get_motion_scale(); + switch (p_anim->track_get_type(p_track)) { + case Animation::TYPE_POSITION_3D: { + if (p_object_sub_idx >= 0) { + Skeleton3D *skel = Object::cast_to(ObjectDB::get_instance(p_object_id)); + if (skel) { + return Vector3(p_value) * skel->get_motion_scale(); + } + } + return p_value; + } break; + default: { + } break; } #endif // _3D_DISABLED return p_value; @@ -978,7 +966,7 @@ void AnimationMixer::_blend_init() { } // Init all value/transform/blend/bezier tracks that track_cache has. - for (const KeyValue &K : track_cache) { + for (const KeyValue &K : track_cache) { TrackCache *track = K.value; track->total_weight = 0.0; @@ -1004,10 +992,6 @@ void AnimationMixer::_blend_init() { t->value = Animation::cast_to_blendwise(t->init_value); t->element_size = t->init_value.is_string() ? (real_t)(t->init_value.operator String()).length() : 0; } break; - case Animation::TYPE_BEZIER: { - TrackCacheBezier *t = static_cast(track); - t->value = t->init_value; - } break; case Animation::TYPE_AUDIO: { TrackCacheAudio *t = static_cast(track); for (KeyValue &L : t->playing_streams) { @@ -1039,12 +1023,12 @@ void AnimationMixer::_blend_calc_total_weight() { if (!a->track_is_enabled(i)) { continue; } - NodePath path = a->track_get_path(i); - if (!track_cache.has(path)) { + Animation::TypeHash thash = a->track_get_type_hash(i); + if (!track_cache.has(thash)) { continue; // No path, but avoid error spamming. } - TrackCache *track = track_cache[path]; - int blend_idx = track_map[path]; + TrackCache *track = track_cache[thash]; + int blend_idx = track_map[track->path]; if (processed_indices.has(blend_idx)) { continue; // There is the case different track type with same path... Is there more faster iterating way than has()? } @@ -1079,13 +1063,13 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (!a->track_is_enabled(i)) { continue; } - NodePath path = a->track_get_path(i); - if (!track_cache.has(path)) { + Animation::TypeHash thash = a->track_get_type_hash(i); + if (!track_cache.has(thash)) { continue; // No path, but avoid error spamming. } - TrackCache *track = track_cache[path]; - ERR_CONTINUE(!track_map.has(path)); - int blend_idx = track_map[path]; + TrackCache *track = track_cache[thash]; + ERR_CONTINUE(!track_map.has(track->path)); + int blend_idx = track_map[track->path]; ERR_CONTINUE(blend_idx < 0 || blend_idx >= track_count); real_t blend = blend_idx < track_weights.size() ? track_weights[blend_idx] * weight : weight; if (!deterministic) { @@ -1097,11 +1081,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { blend = blend / track->total_weight; } Animation::TrackType ttype = a->track_get_type(i); - if (ttype != Animation::TYPE_POSITION_3D && ttype != Animation::TYPE_ROTATION_3D && ttype != Animation::TYPE_SCALE_3D && track->type != ttype) { - // Broken animation, but avoid error spamming. - continue; - } - track->root_motion = root_motion_track == path; + track->root_motion = root_motion_track == a->track_get_path(i); switch (ttype) { case Animation::TYPE_POSITION_3D: { #ifndef _3D_DISABLED @@ -1151,9 +1131,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - loc[0] = post_process_key_value(a, i, loc[0], t->object, t->bone_idx); + loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx); a->try_position_track_interpolate(i, (double)a->get_length(), &loc[1]); - loc[1] = post_process_key_value(a, i, loc[1], t->object, t->bone_idx); + loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx); root_motion_cache.loc += (loc[1] - loc[0]) * blend; prev_time = 0; } @@ -1163,9 +1143,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - loc[0] = post_process_key_value(a, i, loc[0], t->object, t->bone_idx); + loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx); a->try_position_track_interpolate(i, 0, &loc[1]); - loc[1] = post_process_key_value(a, i, loc[1], t->object, t->bone_idx); + loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx); root_motion_cache.loc += (loc[1] - loc[0]) * blend; prev_time = (double)a->get_length(); } @@ -1174,9 +1154,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - loc[0] = post_process_key_value(a, i, loc[0], t->object, t->bone_idx); + loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx); a->try_position_track_interpolate(i, time, &loc[1]); - loc[1] = post_process_key_value(a, i, loc[1], t->object, t->bone_idx); + loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx); root_motion_cache.loc += (loc[1] - loc[0]) * blend; prev_time = !backward ? 0 : (double)a->get_length(); } @@ -1186,7 +1166,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - loc = post_process_key_value(a, i, loc, t->object, t->bone_idx); + loc = post_process_key_value(a, i, loc, t->object_id, t->bone_idx); t->loc += (loc - t->init_loc) * blend; } #endif // _3D_DISABLED @@ -1239,9 +1219,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - rot[0] = post_process_key_value(a, i, rot[0], t->object, t->bone_idx); + rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx); a->try_rotation_track_interpolate(i, (double)a->get_length(), &rot[1]); - rot[1] = post_process_key_value(a, i, rot[1], t->object, t->bone_idx); + rot[1] = post_process_key_value(a, i, rot[1], t->object_id, t->bone_idx); root_motion_cache.rot = (root_motion_cache.rot * Quaternion().slerp(rot[0].inverse() * rot[1], blend)).normalized(); prev_time = 0; } @@ -1251,7 +1231,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - rot[0] = post_process_key_value(a, i, rot[0], t->object, t->bone_idx); + rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx); a->try_rotation_track_interpolate(i, 0, &rot[1]); root_motion_cache.rot = (root_motion_cache.rot * Quaternion().slerp(rot[0].inverse() * rot[1], blend)).normalized(); prev_time = (double)a->get_length(); @@ -1261,9 +1241,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - rot[0] = post_process_key_value(a, i, rot[0], t->object, t->bone_idx); + rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx); a->try_rotation_track_interpolate(i, time, &rot[1]); - rot[1] = post_process_key_value(a, i, rot[1], t->object, t->bone_idx); + rot[1] = post_process_key_value(a, i, rot[1], t->object_id, t->bone_idx); root_motion_cache.rot = (root_motion_cache.rot * Quaternion().slerp(rot[0].inverse() * rot[1], blend)).normalized(); prev_time = !backward ? 0 : (double)a->get_length(); } @@ -1273,7 +1253,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - rot = post_process_key_value(a, i, rot, t->object, t->bone_idx); + rot = post_process_key_value(a, i, rot, t->object_id, t->bone_idx); t->rot = (t->rot * Quaternion().slerp(t->init_rot.inverse() * rot, blend)).normalized(); } #endif // _3D_DISABLED @@ -1326,10 +1306,10 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - scale[0] = post_process_key_value(a, i, scale[0], t->object, t->bone_idx); + scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx); a->try_scale_track_interpolate(i, (double)a->get_length(), &scale[1]); root_motion_cache.scale += (scale[1] - scale[0]) * blend; - scale[1] = post_process_key_value(a, i, scale[1], t->object, t->bone_idx); + scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx); prev_time = 0; } } else { @@ -1338,9 +1318,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - scale[0] = post_process_key_value(a, i, scale[0], t->object, t->bone_idx); + scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx); a->try_scale_track_interpolate(i, 0, &scale[1]); - scale[1] = post_process_key_value(a, i, scale[1], t->object, t->bone_idx); + scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx); root_motion_cache.scale += (scale[1] - scale[0]) * blend; prev_time = (double)a->get_length(); } @@ -1349,9 +1329,9 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - scale[0] = post_process_key_value(a, i, scale[0], t->object, t->bone_idx); + scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx); a->try_scale_track_interpolate(i, time, &scale[1]); - scale[1] = post_process_key_value(a, i, scale[1], t->object, t->bone_idx); + scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx); root_motion_cache.scale += (scale[1] - scale[0]) * blend; prev_time = !backward ? 0 : (double)a->get_length(); } @@ -1361,7 +1341,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - scale = post_process_key_value(a, i, scale, t->object, t->bone_idx); + scale = post_process_key_value(a, i, scale, t->object_id, t->bone_idx); t->scale += (scale - t->init_scale) * blend; } #endif // _3D_DISABLED @@ -1378,18 +1358,19 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (err != OK) { continue; } - value = post_process_key_value(a, i, value, t->object, t->shape_index); + value = post_process_key_value(a, i, value, t->object_id, t->shape_index); t->value += (value - t->init_value) * blend; #endif // _3D_DISABLED } break; + case Animation::TYPE_BEZIER: case Animation::TYPE_VALUE: { if (Math::is_zero_approx(blend)) { continue; // Nothing to blend. } TrackCacheValue *t = static_cast(track); if (t->is_continuous) { - Variant value = a->value_track_interpolate(i, time); - value = post_process_key_value(a, i, value, t->object); + Variant value = ttype == Animation::TYPE_VALUE ? a->value_track_interpolate(i, time) : Variant(a->bezier_track_interpolate(i, time)); + value = post_process_key_value(a, i, value, t->object_id); if (value == Variant()) { continue; } @@ -1429,15 +1410,21 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { continue; } Variant value = a->track_get_key_value(i, idx); - value = post_process_key_value(a, i, value, t->object); - t->object->set_indexed(t->subpath, value); + value = post_process_key_value(a, i, value, t->object_id); + Object *t_obj = ObjectDB::get_instance(t->object_id); + if (t_obj) { + t_obj->set_indexed(t->subpath, value); + } } else { List indices; a->track_get_key_indices_in_range(i, time, delta, &indices, looped_flag); for (int &F : indices) { Variant value = a->track_get_key_value(i, F); - value = post_process_key_value(a, i, value, t->object); - t->object->set_indexed(t->subpath, value); + value = post_process_key_value(a, i, value, t->object_id); + Object *t_obj = ObjectDB::get_instance(t->object_id); + if (t_obj) { + t_obj->set_indexed(t->subpath, value); + } } } } @@ -1459,31 +1446,23 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { } StringName method = a->method_track_get_name(i, idx); Vector params = a->method_track_get_params(i, idx); - _call_object(t->object, method, params, callback_mode_method == ANIMATION_CALLBACK_MODE_METHOD_DEFERRED); + _call_object(t->object_id, method, params, callback_mode_method == ANIMATION_CALLBACK_MODE_METHOD_DEFERRED); } else { List indices; a->track_get_key_indices_in_range(i, time, delta, &indices, looped_flag); for (int &F : indices) { StringName method = a->method_track_get_name(i, F); Vector params = a->method_track_get_params(i, F); - _call_object(t->object, method, params, callback_mode_method == ANIMATION_CALLBACK_MODE_METHOD_DEFERRED); + _call_object(t->object_id, method, params, callback_mode_method == ANIMATION_CALLBACK_MODE_METHOD_DEFERRED); } } } break; - case Animation::TYPE_BEZIER: { - if (Math::is_zero_approx(blend)) { - continue; // Nothing to blend. - } - TrackCacheBezier *t = static_cast(track); - real_t bezier = a->bezier_track_interpolate(i, time); - bezier = post_process_key_value(a, i, bezier, t->object); - t->value += (bezier - t->init_value) * blend; - } break; case Animation::TYPE_AUDIO: { // The end of audio should be observed even if the blend value is 0, build up the information and store to the cache for that. TrackCacheAudio *t = static_cast(track); - Node *asp = Object::cast_to(t->object); - if (!asp) { + Object *t_obj = ObjectDB::get_instance(t->object_id); + Node *asp = t_obj ? Object::cast_to(t_obj) : nullptr; + if (!t_obj || !asp) { t->playing_streams.clear(); continue; } @@ -1533,22 +1512,22 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (seeked) { start_ofs += time - a->track_get_key_time(i, idx); } - if (t->object->call(SNAME("get_stream")) != t->audio_stream) { - t->object->call(SNAME("set_stream"), t->audio_stream); + if (t_obj->call(SNAME("get_stream")) != t->audio_stream) { + t_obj->call(SNAME("set_stream"), t->audio_stream); t->audio_stream_playback.unref(); if (!playing_audio_stream_players.has(asp)) { playing_audio_stream_players.push_back(asp); } } - if (!t->object->call(SNAME("is_playing"))) { - t->object->call(SNAME("play")); + if (!t_obj->call(SNAME("is_playing"))) { + t_obj->call(SNAME("play")); } - if (!t->object->call(SNAME("has_stream_playback"))) { + if (!t_obj->call(SNAME("has_stream_playback"))) { t->audio_stream_playback.unref(); continue; } if (t->audio_stream_playback.is_null()) { - t->audio_stream_playback = t->object->call(SNAME("get_stream_playback")); + t->audio_stream_playback = t_obj->call(SNAME("get_stream_playback")); } PlayingAudioStreamInfo pasi; pasi.index = t->audio_stream_playback->play_stream(stream, start_ofs); @@ -1566,7 +1545,11 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { continue; } TrackCacheAnimation *t = static_cast(track); - AnimationPlayer *player2 = Object::cast_to(t->object); + Object *t_obj = ObjectDB::get_instance(t->object_id); + if (!t_obj) { + continue; + } + AnimationPlayer *player2 = Object::cast_to(t_obj); if (!player2) { continue; } @@ -1633,7 +1616,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { void AnimationMixer::_blend_apply() { // Finally, set the tracks. - for (const KeyValue &K : track_cache) { + for (const KeyValue &K : track_cache) { TrackCache *track = K.value; if (!deterministic && Math::is_zero_approx(track->total_weight)) { continue; @@ -1650,26 +1633,34 @@ void AnimationMixer::_blend_apply() { root_motion_position_accumulator = t->loc; root_motion_rotation_accumulator = t->rot; root_motion_scale_accumulator = t->scale; - } else if (t->skeleton && t->bone_idx >= 0) { + } else if (t->skeleton_id.is_valid() && t->bone_idx >= 0) { + Skeleton3D *t_skeleton = Object::cast_to(ObjectDB::get_instance(t->skeleton_id)); + if (!t_skeleton) { + return; + } if (t->loc_used) { - t->skeleton->set_bone_pose_position(t->bone_idx, t->loc); + t_skeleton->set_bone_pose_position(t->bone_idx, t->loc); } if (t->rot_used) { - t->skeleton->set_bone_pose_rotation(t->bone_idx, t->rot); + t_skeleton->set_bone_pose_rotation(t->bone_idx, t->rot); } if (t->scale_used) { - t->skeleton->set_bone_pose_scale(t->bone_idx, t->scale); + t_skeleton->set_bone_pose_scale(t->bone_idx, t->scale); } - } else if (!t->skeleton) { + } else if (!t->skeleton_id.is_valid()) { + Node3D *t_node_3d = Object::cast_to(ObjectDB::get_instance(t->object_id)); + if (!t_node_3d) { + return; + } if (t->loc_used) { - t->node_3d->set_position(t->loc); + t_node_3d->set_position(t->loc); } if (t->rot_used) { - t->node_3d->set_rotation(t->rot.get_euler()); + t_node_3d->set_rotation(t->rot.get_euler()); } if (t->scale_used) { - t->node_3d->set_scale(t->scale); + t_node_3d->set_scale(t->scale); } } #endif // _3D_DISABLED @@ -1678,8 +1669,9 @@ void AnimationMixer::_blend_apply() { #ifndef _3D_DISABLED TrackCacheBlendShape *t = static_cast(track); - if (t->mesh_3d) { - t->mesh_3d->set_blend_shape_value(t->shape_index, t->value); + MeshInstance3D *t_mesh_3d = Object::cast_to(ObjectDB::get_instance(t->object_id)); + if (t_mesh_3d) { + t_mesh_3d->set_blend_shape_value(t->shape_index, t->value); } #endif // _3D_DISABLED } break; @@ -1703,18 +1695,11 @@ void AnimationMixer::_blend_apply() { } } - // t->object isn't safe here, get instance from id (GH-85365). - Object *obj = ObjectDB::get_instance(t->object_id); - if (obj) { - obj->set_indexed(t->subpath, Animation::cast_from_blendwise(t->value, t->init_value.get_type())); + Object *t_obj = ObjectDB::get_instance(t->object_id); + if (t_obj) { + t_obj->set_indexed(t->subpath, Animation::cast_from_blendwise(t->value, t->init_value.get_type())); } - } break; - case Animation::TYPE_BEZIER: { - TrackCacheBezier *t = static_cast(track); - - t->object->set_indexed(t->subpath, t->value); - } break; case Animation::TYPE_AUDIO: { TrackCacheAudio *t = static_cast(track); @@ -1780,7 +1765,7 @@ void AnimationMixer::_blend_apply() { } } -void AnimationMixer::_call_object(Object *p_object, const StringName &p_method, const Vector &p_params, bool p_deferred) { +void AnimationMixer::_call_object(ObjectID p_object_id, const StringName &p_method, const Vector &p_params, bool p_deferred) { // Separate function to use alloca() more efficiently const Variant **argptrs = (const Variant **)alloca(sizeof(Variant *) * p_params.size()); const Variant *args = p_params.ptr(); @@ -1788,11 +1773,15 @@ void AnimationMixer::_call_object(Object *p_object, const StringName &p_method, for (uint32_t i = 0; i < argcount; i++) { argptrs[i] = &args[i]; } + Object *t_obj = ObjectDB::get_instance(p_object_id); + if (!t_obj) { + return; + } if (p_deferred) { - MessageQueue::get_singleton()->push_callp(p_object, p_method, argptrs, argcount); + MessageQueue::get_singleton()->push_callp(t_obj, p_method, argptrs, argcount); } else { Callable::CallError ce; - p_object->callp(p_method, argptrs, argcount, ce); + t_obj->callp(p_method, argptrs, argcount, ce); } } @@ -1872,7 +1861,7 @@ bool AnimationMixer::can_apply_reset() const { } void AnimationMixer::_build_backup_track_cache() { - for (const KeyValue &K : track_cache) { + for (const KeyValue &K : track_cache) { TrackCache *track = K.value; track->total_weight = 1.0; switch (track->type) { @@ -1881,25 +1870,33 @@ void AnimationMixer::_build_backup_track_cache() { TrackCacheTransform *t = static_cast(track); if (t->root_motion) { // Do nothing. - } else if (t->skeleton && t->bone_idx >= 0) { + } else if (t->skeleton_id.is_valid() && t->bone_idx >= 0) { + Skeleton3D *t_skeleton = Object::cast_to(ObjectDB::get_instance(t->skeleton_id)); + if (!t_skeleton) { + return; + } if (t->loc_used) { - t->loc = t->skeleton->get_bone_pose_position(t->bone_idx); + t->loc = t_skeleton->get_bone_pose_position(t->bone_idx); } if (t->rot_used) { - t->rot = t->skeleton->get_bone_pose_rotation(t->bone_idx); + t->rot = t_skeleton->get_bone_pose_rotation(t->bone_idx); } if (t->scale_used) { - t->scale = t->skeleton->get_bone_pose_scale(t->bone_idx); + t->scale = t_skeleton->get_bone_pose_scale(t->bone_idx); + } + } else if (!t->skeleton_id.is_valid()) { + Node3D *t_node_3d = Object::cast_to(ObjectDB::get_instance(t->object_id)); + if (!t_node_3d) { + return; } - } else if (!t->skeleton) { if (t->loc_used) { - t->loc = t->node_3d->get_position(); + t->loc = t_node_3d->get_position(); } if (t->rot_used) { - t->rot = t->node_3d->get_quaternion(); + t->rot = t_node_3d->get_quaternion(); } if (t->scale_used) { - t->scale = t->node_3d->get_scale(); + t->scale = t_node_3d->get_scale(); } } #endif // _3D_DISABLED @@ -1907,25 +1904,28 @@ void AnimationMixer::_build_backup_track_cache() { case Animation::TYPE_BLEND_SHAPE: { #ifndef _3D_DISABLED TrackCacheBlendShape *t = static_cast(track); - if (t->mesh_3d) { - t->value = t->mesh_3d->get_blend_shape_value(t->shape_index); + MeshInstance3D *t_mesh_3d = Object::cast_to(ObjectDB::get_instance(t->object_id)); + if (t_mesh_3d) { + t->value = t_mesh_3d->get_blend_shape_value(t->shape_index); } #endif // _3D_DISABLED } break; case Animation::TYPE_VALUE: { TrackCacheValue *t = static_cast(track); - t->value = t->object->get_indexed(t->subpath); + Object *t_obj = ObjectDB::get_instance(t->object_id); + if (t_obj) { + t->value = t_obj->get_indexed(t->subpath); + } t->is_continuous = true; } break; - case Animation::TYPE_BEZIER: { - TrackCacheBezier *t = static_cast(track); - t->value = t->object->get_indexed(t->subpath); - } break; case Animation::TYPE_AUDIO: { TrackCacheAudio *t = static_cast(track); - Node *asp = Object::cast_to(t->object); - if (asp) { - t->object->call(SNAME("set_stream"), Ref()); + Object *t_obj = ObjectDB::get_instance(t->object_id); + if (t_obj) { + Node *asp = Object::cast_to(t_obj); + if (asp) { + asp->call(SNAME("set_stream"), Ref()); + } } } break; default: { @@ -1982,7 +1982,7 @@ void AnimationMixer::restore(const Ref &p_backup) { ERR_FAIL_COND(p_backup.is_null()); track_cache = p_backup->get_data(); _blend_apply(); - track_cache = HashMap(); + track_cache = HashMap(); cache_valid = false; } @@ -2113,7 +2113,7 @@ void AnimationMixer::_bind_methods() { /* ---- Blending processor ---- */ ClassDB::bind_method(D_METHOD("clear_caches"), &AnimationMixer::clear_caches); ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationMixer::advance); - GDVIRTUAL_BIND(_post_process_key_value, "animation", "track", "value", "object", "object_idx"); + GDVIRTUAL_BIND(_post_process_key_value, "animation", "track", "value", "object_id", "object_sub_idx"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deterministic"), "set_deterministic", "is_deterministic"); @@ -2159,10 +2159,10 @@ AnimationMixer::AnimationMixer() { AnimationMixer::~AnimationMixer() { } -void AnimatedValuesBackup::set_data(const HashMap &p_data) { +void AnimatedValuesBackup::set_data(const HashMap p_data) { clear_data(); - for (const KeyValue &E : p_data) { + for (const KeyValue &E : p_data) { AnimationMixer::TrackCache *track = get_cache_copy(E.value); if (!track) { continue; // Some types of tracks do not get a copy and must be ignored. @@ -2172,9 +2172,9 @@ void AnimatedValuesBackup::set_data(const HashMap AnimatedValuesBackup::get_data() const { - HashMap ret; - for (const KeyValue &E : data) { +HashMap AnimatedValuesBackup::get_data() const { + HashMap ret; + for (const KeyValue &E : data) { AnimationMixer::TrackCache *track = get_cache_copy(E.value); ERR_CONTINUE(!track); // Backup shouldn't contain tracks that cannot be copied, this is a mistake. @@ -2184,7 +2184,7 @@ HashMap AnimatedValuesBackup::get_data() } void AnimatedValuesBackup::clear_data() { - for (KeyValue &K : data) { + for (KeyValue &K : data) { memdelete(K.value); } data.clear(); @@ -2192,6 +2192,7 @@ void AnimatedValuesBackup::clear_data() { AnimationMixer::TrackCache *AnimatedValuesBackup::get_cache_copy(AnimationMixer::TrackCache *p_cache) const { switch (p_cache->type) { + case Animation::TYPE_BEZIER: case Animation::TYPE_VALUE: { AnimationMixer::TrackCacheValue *src = static_cast(p_cache); AnimationMixer::TrackCacheValue *tc = memnew(AnimationMixer::TrackCacheValue(*src)); @@ -2212,12 +2213,6 @@ AnimationMixer::TrackCache *AnimatedValuesBackup::get_cache_copy(AnimationMixer: return tc; } - case Animation::TYPE_BEZIER: { - AnimationMixer::TrackCacheBezier *src = static_cast(p_cache); - AnimationMixer::TrackCacheBezier *tc = memnew(AnimationMixer::TrackCacheBezier(*src)); - return tc; - } - case Animation::TYPE_AUDIO: { AnimationMixer::TrackCacheAudio *src = static_cast(p_cache); AnimationMixer::TrackCacheAudio *tc = memnew(AnimationMixer::TrackCacheAudio(*src)); diff --git a/scene/animation/animation_mixer.h b/scene/animation/animation_mixer.h index ecc8ab85de4..098c2c3b86b 100644 --- a/scene/animation/animation_mixer.h +++ b/scene/animation/animation_mixer.h @@ -31,9 +31,7 @@ #ifndef ANIMATION_MIXER_H #define ANIMATION_MIXER_H -#include "scene/3d/mesh_instance_3d.h" -#include "scene/3d/node_3d.h" -#include "scene/3d/skeleton_3d.h" +#include "scene/main/node.h" #include "scene/resources/animation.h" #include "scene/resources/animation_library.h" #include "scene/resources/audio_stream_polyphonic.h" @@ -138,7 +136,7 @@ protected: bool root_motion = false; uint64_t setup_pass = 0; Animation::TrackType type = Animation::TrackType::TYPE_ANIMATION; - Object *object = nullptr; + NodePath path; ObjectID object_id; real_t total_weight = 0.0; @@ -147,7 +145,6 @@ protected: root_motion(p_other.root_motion), setup_pass(p_other.setup_pass), type(p_other.type), - object(p_other.object), object_id(p_other.object_id), total_weight(p_other.total_weight) {} @@ -156,8 +153,7 @@ protected: struct TrackCacheTransform : public TrackCache { #ifndef _3D_DISABLED - Node3D *node_3d = nullptr; - Skeleton3D *skeleton = nullptr; + ObjectID skeleton_id; #endif // _3D_DISABLED int bone_idx = -1; bool loc_used = false; @@ -173,8 +169,7 @@ protected: TrackCacheTransform(const TrackCacheTransform &p_other) : TrackCache(p_other), #ifndef _3D_DISABLED - node_3d(p_other.node_3d), - skeleton(p_other.skeleton), + skeleton_id(p_other.skeleton_id), #endif bone_idx(p_other.bone_idx), loc_used(p_other.loc_used), @@ -201,14 +196,12 @@ protected: }; struct TrackCacheBlendShape : public TrackCache { - MeshInstance3D *mesh_3d = nullptr; float init_value = 0; float value = 0; int shape_index = -1; TrackCacheBlendShape(const TrackCacheBlendShape &p_other) : TrackCache(p_other), - mesh_3d(p_other.mesh_3d), init_value(p_other.init_value), value(p_other.value), shape_index(p_other.shape_index) {} @@ -247,23 +240,6 @@ protected: ~TrackCacheMethod() {} }; - struct TrackCacheBezier : public TrackCache { - real_t init_value = 0.0; - real_t value = 0.0; - Vector subpath; - - TrackCacheBezier(const TrackCacheBezier &p_other) : - TrackCache(p_other), - init_value(p_other.init_value), - value(p_other.value), - subpath(p_other.subpath) {} - - TrackCacheBezier() { - type = Animation::TYPE_BEZIER; - } - ~TrackCacheBezier() {} - }; - // Audio stream information for each audio stream placed on the track. struct PlayingAudioStreamInfo { AudioStreamPlaybackPolyphonic::ID index = -1; // ID retrieved from AudioStreamPlaybackPolyphonic. @@ -309,7 +285,7 @@ protected: }; RootMotionCache root_motion_cache; - HashMap track_cache; + HashMap track_cache; HashSet playing_caches; Vector playing_audio_stream_players; @@ -352,9 +328,9 @@ protected: /* ---- Blending processor ---- */ virtual void _process_animation(double p_delta, bool p_update_only = false); - virtual Variant _post_process_key_value(const Ref &p_anim, int p_track, Variant p_value, const Object *p_object, int p_object_idx = -1); - Variant post_process_key_value(const Ref &p_anim, int p_track, Variant p_value, const Object *p_object, int p_object_idx = -1); - GDVIRTUAL5RC(Variant, _post_process_key_value, Ref, int, Variant, Object *, int); + virtual Variant _post_process_key_value(const Ref &p_anim, int p_track, Variant p_value, ObjectID p_object_id, int p_object_sub_idx = -1); + Variant post_process_key_value(const Ref &p_anim, int p_track, Variant p_value, ObjectID p_object_id, int p_object_sub_idx = -1); + GDVIRTUAL5RC(Variant, _post_process_key_value, Ref, int, Variant, ObjectID, int); void _blend_init(); virtual bool _blend_pre_process(double p_delta, int p_track_count, const HashMap &p_track_map); @@ -362,7 +338,13 @@ protected: void _blend_process(double p_delta, bool p_update_only = false); void _blend_apply(); virtual void _blend_post_process(); - void _call_object(Object *p_object, const StringName &p_method, const Vector &p_params, bool p_deferred); + void _call_object(ObjectID p_object_id, const StringName &p_method, const Vector &p_params, bool p_deferred); + +#ifndef DISABLE_DEPRECATED + virtual Variant _post_process_key_value_bind_compat_86687(const Ref &p_anim, int p_track, Variant p_value, Object *p_object, int p_object_idx = -1); + + static void _bind_compatibility_methods(); +#endif // DISABLE_DEPRECATED public: /* ---- Data lists ---- */ @@ -444,11 +426,11 @@ public: class AnimatedValuesBackup : public RefCounted { GDCLASS(AnimatedValuesBackup, RefCounted); - HashMap data; + HashMap data; public: - void set_data(const HashMap &p_data); - HashMap get_data() const; + void set_data(const HashMap p_data); + HashMap get_data() const; void clear_data(); AnimationMixer::TrackCache *get_cache_copy(AnimationMixer::TrackCache *p_cache) const; diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 1ab11cfdf04..e503c79bed0 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -979,6 +979,7 @@ Animation::TrackType Animation::track_get_type(int p_track) const { void Animation::track_set_path(int p_track, const NodePath &p_path) { ERR_FAIL_INDEX(p_track, tracks.size()); tracks[p_track]->path = p_path; + _track_update_hash(p_track); emit_changed(); } @@ -996,6 +997,27 @@ int Animation::find_track(const NodePath &p_path, const TrackType p_type) const return -1; }; +Animation::TrackType Animation::get_cache_type(TrackType p_type) { + if (p_type == Animation::TYPE_BEZIER) { + return Animation::TYPE_VALUE; + } + if (p_type == Animation::TYPE_ROTATION_3D || p_type == Animation::TYPE_SCALE_3D) { + return Animation::TYPE_POSITION_3D; // Reference them as position3D tracks, even if they modify rotation or scale. + } + return p_type; +} + +void Animation::_track_update_hash(int p_track) { + NodePath track_path = tracks[p_track]->path; + TrackType track_cache_type = get_cache_type(tracks[p_track]->type); + tracks[p_track]->thash = StringName(String(track_path.get_concatenated_names()) + String(track_path.get_concatenated_subnames()) + itos(track_cache_type)).hash(); +} + +Animation::TypeHash Animation::track_get_type_hash(int p_track) const { + ERR_FAIL_INDEX_V(p_track, tracks.size(), 0); + return tracks[p_track]->thash; +} + void Animation::track_set_interpolation_type(int p_track, InterpolationType p_interp) { ERR_FAIL_INDEX(p_track, tracks.size()); tracks[p_track]->interpolation = p_interp; diff --git a/scene/resources/animation.h b/scene/resources/animation.h index 54a78fffa42..6c31bbcd297 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -41,6 +41,8 @@ class Animation : public Resource { RES_BASE_EXTENSION("anim"); public: + typedef uint32_t TypeHash; + enum TrackType { TYPE_VALUE, ///< Set a value in a property, can be interpolated. TYPE_POSITION_3D, ///< Position 3D track @@ -104,7 +106,8 @@ private: TrackType type = TrackType::TYPE_ANIMATION; InterpolationType interpolation = INTERPOLATION_LINEAR; bool loop_wrap = true; - NodePath path; // path to something + NodePath path; // Path to something. + TypeHash thash = 0; // Hash by Path + SubPath + TrackType. bool imported = false; bool enabled = true; Track() {} @@ -268,6 +271,8 @@ private: real_t step = 0.1; LoopMode loop_mode = LOOP_NONE; + void _track_update_hash(int p_track); + /* Animation compression page format (version 1): * * Animation uses bitwidth based compression separated into small pages. The intention is that pages fit easily in the cache, so decoding is cache efficient. @@ -386,6 +391,8 @@ public: NodePath track_get_path(int p_track) const; int find_track(const NodePath &p_path, const TrackType p_type) const; + TypeHash track_get_type_hash(int p_track) const; + void track_move_up(int p_track); void track_move_down(int p_track); void track_move_to(int p_track, int p_to_index); @@ -504,6 +511,8 @@ public: static Variant interpolate_variant(const Variant &a, const Variant &b, float c, bool p_snap_array_element = false); static Variant cubic_interpolate_in_time_variant(const Variant &pre_a, const Variant &a, const Variant &b, const Variant &post_b, float c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t, bool p_snap_array_element = false); + static TrackType get_cache_type(TrackType p_type); + Animation(); ~Animation(); };