From cbf888896da69cfe1cb512eec163110d546a7d9b Mon Sep 17 00:00:00 2001 From: "Silc Lizard (Tokage) Renew" <61938263+TokageItLab@users.noreply.github.com> Date: Wed, 26 Nov 2025 21:00:53 +0900 Subject: [PATCH] Refert: Fix AHashMap realloc cause AnimationPlayer crash --- scene/animation/animation_player.cpp | 73 +++++++++++++--------------- scene/animation/animation_player.h | 9 ++-- 2 files changed, 38 insertions(+), 44 deletions(-) diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 033dce4f3a8..2aaed507bed 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -164,11 +164,10 @@ void AnimationPlayer::_process_playback_data(PlaybackData &cd, double p_delta, f double start = cd.get_start_time(); double end = cd.get_end_time(); - AnimationData *p_from = &animation_set[cd.animation_name]; Animation::LoopedFlag looped_flag = Animation::LOOPED_FLAG_NONE; - switch (p_from->animation->get_loop_mode()) { + switch (cd.from->animation->get_loop_mode()) { case Animation::LOOP_NONE: { if (Animation::is_less_approx(next_pos, start)) { next_pos = start; @@ -208,7 +207,7 @@ void AnimationPlayer::_process_playback_data(PlaybackData &cd, double p_delta, f // End detection. if (p_is_current) { - if (p_from->animation->get_loop_mode() == Animation::LOOP_NONE) { + if (cd.from->animation->get_loop_mode() == Animation::LOOP_NONE) { if (!backwards && Animation::is_less_or_equal_approx(prev_pos, end) && Math::is_equal_approx(next_pos, end)) { // Playback finished. next_pos = end; // Snap to the edge. @@ -249,7 +248,7 @@ void AnimationPlayer::_process_playback_data(PlaybackData &cd, double p_delta, f pi.is_external_seeking = !p_internal_seeked && !p_started; pi.looped_flag = looped_flag; pi.weight = p_blend; - make_animation_instance(cd.animation_name, pi); + make_animation_instance(cd.from->name, pi); } float AnimationPlayer::get_current_blend_amount() { @@ -301,13 +300,12 @@ void AnimationPlayer::_blend_playback_data(double p_delta, bool p_started) { } bool AnimationPlayer::_blend_pre_process(double p_delta, int p_track_count, const AHashMap &p_track_map) { - if (playback.current.animation_name.is_empty()) { + if (!playback.current.from) { _set_process(false); return false; } - AnimationData *p_from = &animation_set[playback.current.animation_name]; - tmp_from = p_from->animation->get_instance_id(); + tmp_from = playback.current.from->animation->get_instance_id(); end_reached = false; end_notify = false; @@ -318,10 +316,10 @@ bool AnimationPlayer::_blend_pre_process(double p_delta, int p_track_count, cons playback.started = false; } - String prev_animation_name = playback.current.animation_name; + AnimationData *prev_from = playback.current.from; _blend_playback_data(p_delta, started); - if (prev_animation_name != playback.current.animation_name) { + if (prev_from != playback.current.from) { return false; // Animation has been changed in the process (may be caused by method track), abort process. } @@ -335,7 +333,7 @@ void AnimationPlayer::_blend_capture(double p_delta) { void AnimationPlayer::_blend_post_process() { if (end_reached) { // If the method track changes current animation, the animation is not finished. - if (tmp_from == animation_set[playback.current.animation_name].animation->get_instance_id()) { + if (tmp_from == playback.current.from->animation->get_instance_id()) { if (playback_queue.size()) { if (!finished_anim.is_empty()) { emit_signal(SceneStringName(animation_finished), finished_anim); @@ -435,10 +433,10 @@ void AnimationPlayer::play_section_with_markers(const StringName &p_name, const ERR_FAIL_COND_MSG(p_start_marker && p_end_marker && Animation::is_greater_approx(start_time, end_time), vformat("End marker %s is placed earlier than start marker %s in animation: %s.", p_end_marker, p_start_marker, name)); if (p_start_marker && Animation::is_less_approx(start_time, 0)) { - WARN_PRINT_ED(vformat("Negative time start marker: %s is invalid in the section, so the start of the animation: %s is used instead.", p_start_marker, playback.current.animation_name)); + WARN_PRINT_ED(vformat("Negative time start marker: %s is invalid in the section, so the start of the animation: %s is used instead.", p_start_marker, playback.current.from->animation->get_name())); } if (p_end_marker && Animation::is_less_approx(end_time, 0)) { - WARN_PRINT_ED(vformat("Negative time end marker: %s is invalid in the section, so the end of the animation: %s is used instead.", p_end_marker, playback.current.animation_name)); + WARN_PRINT_ED(vformat("Negative time end marker: %s is invalid in the section, so the end of the animation: %s is used instead.", p_end_marker, playback.current.from->animation->get_name())); } play_section(name, start_time, end_time, p_custom_blend, p_custom_scale, p_from_end); @@ -457,11 +455,11 @@ void AnimationPlayer::play_section(const StringName &p_name, double p_start_time Playback &c = playback; - if (!c.current.animation_name.is_empty()) { + if (c.current.from) { double blend_time = 0.0; // Find if it can blend. BlendKey bk; - bk.from = c.current.animation_name; + bk.from = c.current.from->name; bk.to = name; if (Animation::is_greater_or_equal_approx(p_custom_blend, 0)) { @@ -473,7 +471,7 @@ void AnimationPlayer::play_section(const StringName &p_name, double p_start_time if (blend_times.has(bk)) { blend_time = blend_times[bk]; } else { - bk.from = c.current.animation_name; + bk.from = c.current.from->name; bk.to = "*"; if (blend_times.has(bk)) { @@ -500,8 +498,7 @@ void AnimationPlayer::play_section(const StringName &p_name, double p_start_time _clear_playing_caches(); } - c.current.animation_name = name; - c.current.animation_length = animation_set[name].animation->get_length(); + c.current.from = &animation_set[name]; c.current.speed_scale = p_custom_scale; c.current.start_time = p_start_time; c.current.end_time = p_end_time; @@ -616,8 +613,7 @@ void AnimationPlayer::set_assigned_animation(const StringName &p_animation) { } else { ERR_FAIL_COND_MSG(!animation_set.has(p_animation), vformat("Animation not found: %s.", p_animation.operator String())); playback.current.pos = 0; - playback.current.animation_name = p_animation; - playback.current.animation_length = animation_set[p_animation].animation->get_length(); + playback.current.from = &animation_set[p_animation]; playback.current.start_time = -1; playback.current.end_time = -1; playback.assigned = p_animation; @@ -662,13 +658,12 @@ void AnimationPlayer::seek_internal(double p_time, bool p_update, bool p_update_ _check_immediately_after_start(); playback.current.pos = p_time; - if (!playback.current.animation_name.is_empty()) { + if (!playback.current.from) { if (playback.assigned) { ERR_FAIL_COND_MSG(!animation_set.has(playback.assigned), vformat("Animation not found: %s.", playback.assigned)); - playback.current.animation_name = playback.assigned; - playback.current.animation_length = animation_set[playback.assigned].animation->get_length(); + playback.current.from = &animation_set[playback.assigned]; } - if (!playback.current.animation_name.is_empty()) { + if (!playback.current.from) { return; // There is no animation. } } @@ -704,37 +699,37 @@ void AnimationPlayer::_check_immediately_after_start() { } bool AnimationPlayer::is_valid() const { - return (!playback.current.animation_name.is_empty()); + return (playback.current.from); } double AnimationPlayer::get_current_animation_position() const { - ERR_FAIL_COND_V_MSG(!playback.current.animation_name.is_empty(), 0, "AnimationPlayer has no current animation."); + ERR_FAIL_NULL_V_MSG(playback.current.from, 0, "AnimationPlayer has no current animation."); return playback.current.pos; } double AnimationPlayer::get_current_animation_length() const { - ERR_FAIL_COND_V_MSG(!playback.current.animation_name.is_empty(), 0, "AnimationPlayer has no current animation."); - return playback.current.animation_length; + ERR_FAIL_NULL_V_MSG(playback.current.from, 0, "AnimationPlayer has no current animation."); + return playback.current.from->animation->get_length(); } void AnimationPlayer::set_section_with_markers(const StringName &p_start_marker, const StringName &p_end_marker) { - ERR_FAIL_COND_MSG(!playback.current.animation_name.is_empty(), "AnimationPlayer has no current animation."); + ERR_FAIL_NULL_MSG(playback.current.from, "AnimationPlayer has no current animation."); ERR_FAIL_COND_MSG(p_start_marker == p_end_marker && p_start_marker, vformat("Start marker and end marker cannot be the same marker: %s.", p_start_marker)); - ERR_FAIL_COND_MSG(p_start_marker && !animation_set[playback.current.animation_name].animation->has_marker(p_start_marker), vformat("Marker %s not found in animation: %s.", p_start_marker, playback.current.animation_name)); - ERR_FAIL_COND_MSG(p_end_marker && !animation_set[playback.current.animation_name].animation->has_marker(p_end_marker), vformat("Marker %s not found in animation: %s.", p_end_marker, playback.current.animation_name)); - double start_time = p_start_marker ? animation_set[playback.current.animation_name].animation->get_marker_time(p_start_marker) : -1; - double end_time = p_end_marker ? animation_set[playback.current.animation_name].animation->get_marker_time(p_end_marker) : -1; + ERR_FAIL_COND_MSG(p_start_marker && !playback.current.from->animation->has_marker(p_start_marker), vformat("Marker %s not found in animation: %s.", p_start_marker, playback.current.from->animation->get_name())); + ERR_FAIL_COND_MSG(p_end_marker && !playback.current.from->animation->has_marker(p_end_marker), vformat("Marker %s not found in animation: %s.", p_end_marker, playback.current.from->animation->get_name())); + double start_time = p_start_marker ? playback.current.from->animation->get_marker_time(p_start_marker) : -1; + double end_time = p_end_marker ? playback.current.from->animation->get_marker_time(p_end_marker) : -1; if (p_start_marker && Animation::is_less_approx(start_time, 0)) { - WARN_PRINT_ONCE_ED(vformat("Marker %s time must be positive in animation: %s.", p_start_marker, playback.current.animation_name)); + WARN_PRINT_ONCE_ED(vformat("Marker %s time must be positive in animation: %s.", p_start_marker, playback.current.from->animation->get_name())); } if (p_end_marker && Animation::is_less_approx(end_time, 0)) { - WARN_PRINT_ONCE_ED(vformat("Marker %s time must be positive in animation: %s.", p_end_marker, playback.current.animation_name)); + WARN_PRINT_ONCE_ED(vformat("Marker %s time must be positive in animation: %s.", p_end_marker, playback.current.from->animation->get_name())); } set_section(start_time, end_time); } void AnimationPlayer::set_section(double p_start_time, double p_end_time) { - ERR_FAIL_COND_MSG(!playback.current.animation_name.is_empty(), "AnimationPlayer has no current animation."); + ERR_FAIL_NULL_MSG(playback.current.from, "AnimationPlayer has no current animation."); ERR_FAIL_COND_MSG(Animation::is_greater_or_equal_approx(p_start_time, 0) && Animation::is_greater_or_equal_approx(p_end_time, 0) && Animation::is_greater_or_equal_approx(p_start_time, p_end_time), vformat("Start time %f is greater than end time %f.", p_start_time, p_end_time)); playback.current.start_time = p_start_time; playback.current.end_time = p_end_time; @@ -747,12 +742,12 @@ void AnimationPlayer::reset_section() { } double AnimationPlayer::get_section_start_time() const { - ERR_FAIL_COND_V_MSG(!playback.current.animation_name.is_empty(), playback.current.start_time, "AnimationPlayer has no current animation."); + ERR_FAIL_NULL_V_MSG(playback.current.from, playback.current.start_time, "AnimationPlayer has no current animation."); return playback.current.get_start_time(); } double AnimationPlayer::get_section_end_time() const { - ERR_FAIL_COND_V_MSG(!playback.current.animation_name.is_empty(), playback.current.end_time, "AnimationPlayer has no current animation."); + ERR_FAIL_NULL_V_MSG(playback.current.from, playback.current.end_time, "AnimationPlayer has no current animation."); return playback.current.get_end_time(); } @@ -784,7 +779,7 @@ void AnimationPlayer::_stop_internal(bool p_reset, bool p_keep_state) { _clear_caches(); Playback &c = playback; // c.blend.clear(); - double start = (!c.current.animation_name.is_empty()) ? playback.current.get_start_time() : 0; + double start = c.current.from ? playback.current.get_start_time() : 0; if (p_reset) { c.blend.clear(); if (p_keep_state) { @@ -794,7 +789,7 @@ void AnimationPlayer::_stop_internal(bool p_reset, bool p_keep_state) { seek_internal(start, true, true, true); is_stopping = false; } - c.current.animation_name = String(); + c.current.from = nullptr; c.current.speed_scale = 1; emit_signal(SNAME("current_animation_changed"), ""); } diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index ffeb552859c..4aa2411d0a2 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -65,21 +65,20 @@ private: bool is_stopping = false; struct PlaybackData { - String animation_name; - int animation_length = 0; + AnimationData *from = nullptr; double pos = 0.0; float speed_scale = 1.0; double start_time = 0.0; double end_time = 0.0; double get_start_time() const { - if ((!animation_name.is_empty()) && (Animation::is_less_approx(start_time, 0) || Animation::is_greater_approx(start_time, animation_length))) { + if (from && (Animation::is_less_approx(start_time, 0) || Animation::is_greater_approx(start_time, from->animation->get_length()))) { return 0; } return start_time; } double get_end_time() const { - if ((!animation_name.is_empty()) && (Animation::is_less_approx(end_time, 0) || Animation::is_greater_approx(end_time, animation_length))) { - return animation_length; + if (from && (Animation::is_less_approx(end_time, 0) || Animation::is_greater_approx(end_time, from->animation->get_length()))) { + return from->animation->get_length(); } return end_time; }