Forráskód Böngészése

Fix seeking Animation immediate after playback for Discrete track

Silc Lizard (Tokage) Renew 1 éve
szülő
commit
bea47d877b

+ 4 - 0
doc/classes/Animation.xml

@@ -360,9 +360,12 @@
 			<param index="1" name="time" type="float" />
 			<param index="1" name="time" type="float" />
 			<param index="2" name="find_mode" type="int" enum="Animation.FindMode" default="0" />
 			<param index="2" name="find_mode" type="int" enum="Animation.FindMode" default="0" />
 			<param index="3" name="limit" type="bool" default="false" />
 			<param index="3" name="limit" type="bool" default="false" />
+			<param index="4" name="backward" type="bool" default="false" />
 			<description>
 			<description>
 				Finds the key index by time in a given track. Optionally, only find it if the approx/exact time is given.
 				Finds the key index by time in a given track. Optionally, only find it if the approx/exact time is given.
 				If [param limit] is [code]true[/code], it does not return keys outside the animation range.
 				If [param limit] is [code]true[/code], it does not return keys outside the animation range.
+				If [param backward] is [code]true[/code], the direction is reversed in methods that rely on one directional processing.
+				For example, in case [param find_mode] is [constant FIND_MODE_NEAREST], if there is no key in the current position just after seeked, the first key found is retrieved by searching before the position, but if [param backward] is [code]true[/code], the first key found is retrieved after the position.
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="track_get_interpolation_loop_wrap" qualifiers="const">
 		<method name="track_get_interpolation_loop_wrap" qualifiers="const">
@@ -583,6 +586,7 @@
 			<param index="2" name="backward" type="bool" default="false" />
 			<param index="2" name="backward" type="bool" default="false" />
 			<description>
 			<description>
 				Returns the interpolated value at the given time (in seconds). The [param track_idx] must be the index of a value track.
 				Returns the interpolated value at the given time (in seconds). The [param track_idx] must be the index of a value track.
+				A [param backward] mainly affects the direction of key retrieval of the track with [constant UPDATE_DISCRETE] converted by [constant AnimationMixer.ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS] to match the result with [method track_find_key].
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="value_track_set_update_mode">
 		<method name="value_track_set_update_mode">

+ 7 - 7
editor/plugins/animation_player_editor_plugin.cpp

@@ -243,12 +243,12 @@ void AnimationPlayerEditor::_play_from_pressed() {
 	String current = _get_current();
 	String current = _get_current();
 
 
 	if (!current.is_empty()) {
 	if (!current.is_empty()) {
-		float time = player->get_current_animation_position();
+		double time = player->get_current_animation_position();
 		if (current == player->get_assigned_animation() && player->is_playing()) {
 		if (current == player->get_assigned_animation() && player->is_playing()) {
-			player->stop(); //so it won't blend with itself
+			player->clear_caches(); //so it won't blend with itself
 		}
 		}
 		ERR_FAIL_COND_EDMSG(!_validate_tracks(player->get_animation(current)), "Animation tracks may have any invalid key, abort playing.");
 		ERR_FAIL_COND_EDMSG(!_validate_tracks(player->get_animation(current)), "Animation tracks may have any invalid key, abort playing.");
-		player->seek(time);
+		player->seek(time, true, true);
 		player->play(current);
 		player->play(current);
 	}
 	}
 
 
@@ -281,12 +281,12 @@ void AnimationPlayerEditor::_play_bw_from_pressed() {
 	String current = _get_current();
 	String current = _get_current();
 
 
 	if (!current.is_empty()) {
 	if (!current.is_empty()) {
-		float time = player->get_current_animation_position();
-		if (current == player->get_assigned_animation()) {
-			player->stop(); //so it won't blend with itself
+		double time = player->get_current_animation_position();
+		if (current == player->get_assigned_animation() && player->is_playing()) {
+			player->clear_caches(); //so it won't blend with itself
 		}
 		}
 		ERR_FAIL_COND_EDMSG(!_validate_tracks(player->get_animation(current)), "Animation tracks may have any invalid key, abort playing.");
 		ERR_FAIL_COND_EDMSG(!_validate_tracks(player->get_animation(current)), "Animation tracks may have any invalid key, abort playing.");
-		player->seek(time);
+		player->seek(time, true, true);
 		player->play_backwards(current);
 		player->play_backwards(current);
 	}
 	}
 
 

+ 6 - 0
misc/extension_api_validation/4.2-stable.expected

@@ -364,3 +364,9 @@ GH-92322
 Validate extension JSON: Error: Field 'classes/EditorInspectorPlugin/methods/add_property_editor/arguments': size changed value in new API, from 3 to 4.
 Validate extension JSON: Error: Field 'classes/EditorInspectorPlugin/methods/add_property_editor/arguments': size changed value in new API, from 3 to 4.
 
 
 Optional arguments added. Compatibility methods registered.
 Optional arguments added. Compatibility methods registered.
+
+GH-86661
+--------
+Validate extension JSON: Error: Field 'classes/Animation/methods/track_find_key/arguments': size changed value in new API, from 3 to 5.
+
+Added optional argument to track_find_key to handle backward seeking. Compatibility method registered.

+ 7 - 6
scene/animation/animation_mixer.cpp

@@ -1109,6 +1109,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
 		real_t weight = ai.playback_info.weight;
 		real_t weight = ai.playback_info.weight;
 		Vector<real_t> track_weights = ai.playback_info.track_weights;
 		Vector<real_t> track_weights = ai.playback_info.track_weights;
 		bool backward = signbit(delta); // This flag is used by the root motion calculates or detecting the end of audio stream.
 		bool backward = signbit(delta); // This flag is used by the root motion calculates or detecting the end of audio stream.
+		bool seeked_backward = signbit(p_delta);
 #ifndef _3D_DISABLED
 #ifndef _3D_DISABLED
 		bool calc_root = !seeked || is_external_seeking;
 		bool calc_root = !seeked || is_external_seeking;
 #endif // _3D_DISABLED
 #endif // _3D_DISABLED
@@ -1463,7 +1464,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
 						}
 						}
 					} else {
 					} else {
 						if (seeked) {
 						if (seeked) {
-							int idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT, true);
+							int idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT, false, seeked_backward);
 							if (idx < 0) {
 							if (idx < 0) {
 								continue;
 								continue;
 							}
 							}
@@ -1744,8 +1745,10 @@ void AnimationMixer::_blend_apply() {
 			case Animation::TYPE_VALUE: {
 			case Animation::TYPE_VALUE: {
 				TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
 				TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
 
 
-				if (t->use_discrete && !t->use_continuous) {
-					t->is_init = true; // If only disctere value is applied, no more RESET.
+				if (callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS) {
+					t->is_init = false; // Always update in Force Continuous.
+				} else if (!t->use_continuous && (t->use_discrete || !deterministic)) {
+					t->is_init = true; // If there is no continuous value and only disctere value is applied or just started, don't RESET.
 				}
 				}
 
 
 				if ((t->is_init && (is_zero_amount || !t->use_continuous)) ||
 				if ((t->is_init && (is_zero_amount || !t->use_continuous)) ||
@@ -1756,9 +1759,7 @@ void AnimationMixer::_blend_apply() {
 					break; // Don't overwrite the value set by UPDATE_DISCRETE.
 					break; // Don't overwrite the value set by UPDATE_DISCRETE.
 				}
 				}
 
 
-				if (callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS) {
-					t->is_init = false; // Always update in Force Continuous.
-				} else {
+				if (callback_mode_discrete != ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS) {
 					t->is_init = !t->use_continuous; // If there is no Continuous in non-Force Continuous type, it means RESET.
 					t->is_init = !t->use_continuous; // If there is no Continuous in non-Force Continuous type, it means RESET.
 				}
 				}
 
 

+ 7 - 2
scene/animation/animation_player.cpp

@@ -234,6 +234,9 @@ void AnimationPlayer::_process_playback_data(PlaybackData &cd, double p_delta, f
 		pi.delta = delta;
 		pi.delta = delta;
 		pi.seeked = p_seeked;
 		pi.seeked = p_seeked;
 	}
 	}
+	if (Math::is_zero_approx(pi.delta) && backwards) {
+		pi.delta = -0.0; // Sign is needed to handle converted Continuous track from Discrete track correctly.
+	}
 	// AnimationPlayer doesn't have internal seeking.
 	// AnimationPlayer doesn't have internal seeking.
 	// However, immediately after playback, discrete keys should be retrieved with EXACT mode since behind keys must be ignored at that time.
 	// However, immediately after playback, discrete keys should be retrieved with EXACT mode since behind keys must be ignored at that time.
 	pi.is_external_seeking = !p_started;
 	pi.is_external_seeking = !p_started;
@@ -257,7 +260,7 @@ void AnimationPlayer::_blend_playback_data(double p_delta, bool p_started) {
 
 
 	bool seeked = c.seeked; // The animation may be changed during process, so it is safer that the state is changed before process.
 	bool seeked = c.seeked; // The animation may be changed during process, so it is safer that the state is changed before process.
 
 
-	if (p_delta != 0) {
+	if (!Math::is_zero_approx(p_delta)) {
 		c.seeked = false;
 		c.seeked = false;
 	}
 	}
 
 
@@ -581,6 +584,8 @@ void AnimationPlayer::seek(double p_time, bool p_update, bool p_update_only) {
 		return;
 		return;
 	}
 	}
 
 
+	bool is_backward = p_time < playback.current.pos;
+
 	_check_immediately_after_start();
 	_check_immediately_after_start();
 
 
 	playback.current.pos = p_time;
 	playback.current.pos = p_time;
@@ -596,7 +601,7 @@ void AnimationPlayer::seek(double p_time, bool p_update, bool p_update_only) {
 
 
 	playback.seeked = true;
 	playback.seeked = true;
 	if (p_update) {
 	if (p_update) {
-		_process_animation(0, p_update_only);
+		_process_animation(is_backward ? -0.0 : 0.0, p_update_only);
 		playback.seeked = false; // If animation was proceeded here, no more seek in internal process.
 		playback.seeked = false; // If animation was proceeded here, no more seek in internal process.
 	}
 	}
 }
 }

+ 3 - 3
scene/resources/animation.compat.inc

@@ -50,8 +50,8 @@ Variant Animation::_value_track_interpolate_bind_compat_86629(int p_track, doubl
 	return value_track_interpolate(p_track, p_time, false);
 	return value_track_interpolate(p_track, p_time, false);
 }
 }
 
 
-int Animation::_track_find_key_bind_compat_86661(int p_track, double p_time, FindMode p_find_mode) const {
-	return track_find_key(p_track, p_time, p_find_mode, false);
+int Animation::_track_find_key_bind_compat_92861(int p_track, double p_time, FindMode p_find_mode) const {
+	return track_find_key(p_track, p_time, p_find_mode, false, false);
 }
 }
 
 
 void Animation::_bind_compatibility_methods() {
 void Animation::_bind_compatibility_methods() {
@@ -60,7 +60,7 @@ void Animation::_bind_compatibility_methods() {
 	ClassDB::bind_compatibility_method(D_METHOD("scale_track_interpolate", "track_idx", "time_sec"), &Animation::_scale_track_interpolate_bind_compat_86629);
 	ClassDB::bind_compatibility_method(D_METHOD("scale_track_interpolate", "track_idx", "time_sec"), &Animation::_scale_track_interpolate_bind_compat_86629);
 	ClassDB::bind_compatibility_method(D_METHOD("blend_shape_track_interpolate", "track_idx", "time_sec"), &Animation::_blend_shape_track_interpolate_bind_compat_86629);
 	ClassDB::bind_compatibility_method(D_METHOD("blend_shape_track_interpolate", "track_idx", "time_sec"), &Animation::_blend_shape_track_interpolate_bind_compat_86629);
 	ClassDB::bind_compatibility_method(D_METHOD("value_track_interpolate", "track_idx", "time_sec"), &Animation::_value_track_interpolate_bind_compat_86629);
 	ClassDB::bind_compatibility_method(D_METHOD("value_track_interpolate", "track_idx", "time_sec"), &Animation::_value_track_interpolate_bind_compat_86629);
-	ClassDB::bind_compatibility_method(D_METHOD("track_find_key", "track_idx", "time", "find_mode"), &Animation::_track_find_key_bind_compat_86661, DEFVAL(FIND_MODE_NEAREST));
+	ClassDB::bind_compatibility_method(D_METHOD("track_find_key", "track_idx", "time", "find_mode"), &Animation::_track_find_key_bind_compat_92861, DEFVAL(FIND_MODE_NEAREST));
 }
 }
 
 
 #endif // DISABLE_DEPRECATED
 #endif // DISABLE_DEPRECATED

+ 11 - 11
scene/resources/animation.cpp

@@ -1496,7 +1496,7 @@ void Animation::track_remove_key(int p_track, int p_idx) {
 	emit_changed();
 	emit_changed();
 }
 }
 
 
-int Animation::track_find_key(int p_track, double p_time, FindMode p_find_mode, bool p_limit) const {
+int Animation::track_find_key(int p_track, double p_time, FindMode p_find_mode, bool p_limit, bool p_backward) const {
 	ERR_FAIL_INDEX_V(p_track, tracks.size(), -1);
 	ERR_FAIL_INDEX_V(p_track, tracks.size(), -1);
 	Track *t = tracks[p_track];
 	Track *t = tracks[p_track];
 
 
@@ -1518,7 +1518,7 @@ int Animation::track_find_key(int p_track, double p_time, FindMode p_find_mode,
 				return key_index;
 				return key_index;
 			}
 			}
 
 
-			int k = _find(tt->positions, p_time, false, p_limit);
+			int k = _find(tt->positions, p_time, p_backward, p_limit);
 			if (k < 0 || k >= tt->positions.size()) {
 			if (k < 0 || k >= tt->positions.size()) {
 				return -1;
 				return -1;
 			}
 			}
@@ -1545,7 +1545,7 @@ int Animation::track_find_key(int p_track, double p_time, FindMode p_find_mode,
 				return key_index;
 				return key_index;
 			}
 			}
 
 
-			int k = _find(rt->rotations, p_time, false, p_limit);
+			int k = _find(rt->rotations, p_time, p_backward, p_limit);
 			if (k < 0 || k >= rt->rotations.size()) {
 			if (k < 0 || k >= rt->rotations.size()) {
 				return -1;
 				return -1;
 			}
 			}
@@ -1572,7 +1572,7 @@ int Animation::track_find_key(int p_track, double p_time, FindMode p_find_mode,
 				return key_index;
 				return key_index;
 			}
 			}
 
 
-			int k = _find(st->scales, p_time, false, p_limit);
+			int k = _find(st->scales, p_time, p_backward, p_limit);
 			if (k < 0 || k >= st->scales.size()) {
 			if (k < 0 || k >= st->scales.size()) {
 				return -1;
 				return -1;
 			}
 			}
@@ -1599,7 +1599,7 @@ int Animation::track_find_key(int p_track, double p_time, FindMode p_find_mode,
 				return key_index;
 				return key_index;
 			}
 			}
 
 
-			int k = _find(bst->blend_shapes, p_time, false, p_limit);
+			int k = _find(bst->blend_shapes, p_time, p_backward, p_limit);
 			if (k < 0 || k >= bst->blend_shapes.size()) {
 			if (k < 0 || k >= bst->blend_shapes.size()) {
 				return -1;
 				return -1;
 			}
 			}
@@ -1611,7 +1611,7 @@ int Animation::track_find_key(int p_track, double p_time, FindMode p_find_mode,
 		} break;
 		} break;
 		case TYPE_VALUE: {
 		case TYPE_VALUE: {
 			ValueTrack *vt = static_cast<ValueTrack *>(t);
 			ValueTrack *vt = static_cast<ValueTrack *>(t);
-			int k = _find(vt->values, p_time, false, p_limit);
+			int k = _find(vt->values, p_time, p_backward, p_limit);
 			if (k < 0 || k >= vt->values.size()) {
 			if (k < 0 || k >= vt->values.size()) {
 				return -1;
 				return -1;
 			}
 			}
@@ -1623,7 +1623,7 @@ int Animation::track_find_key(int p_track, double p_time, FindMode p_find_mode,
 		} break;
 		} break;
 		case TYPE_METHOD: {
 		case TYPE_METHOD: {
 			MethodTrack *mt = static_cast<MethodTrack *>(t);
 			MethodTrack *mt = static_cast<MethodTrack *>(t);
-			int k = _find(mt->methods, p_time, false, p_limit);
+			int k = _find(mt->methods, p_time, p_backward, p_limit);
 			if (k < 0 || k >= mt->methods.size()) {
 			if (k < 0 || k >= mt->methods.size()) {
 				return -1;
 				return -1;
 			}
 			}
@@ -1635,7 +1635,7 @@ int Animation::track_find_key(int p_track, double p_time, FindMode p_find_mode,
 		} break;
 		} break;
 		case TYPE_BEZIER: {
 		case TYPE_BEZIER: {
 			BezierTrack *bt = static_cast<BezierTrack *>(t);
 			BezierTrack *bt = static_cast<BezierTrack *>(t);
-			int k = _find(bt->values, p_time, false, p_limit);
+			int k = _find(bt->values, p_time, p_backward, p_limit);
 			if (k < 0 || k >= bt->values.size()) {
 			if (k < 0 || k >= bt->values.size()) {
 				return -1;
 				return -1;
 			}
 			}
@@ -1647,7 +1647,7 @@ int Animation::track_find_key(int p_track, double p_time, FindMode p_find_mode,
 		} break;
 		} break;
 		case TYPE_AUDIO: {
 		case TYPE_AUDIO: {
 			AudioTrack *at = static_cast<AudioTrack *>(t);
 			AudioTrack *at = static_cast<AudioTrack *>(t);
-			int k = _find(at->values, p_time, false, p_limit);
+			int k = _find(at->values, p_time, p_backward, p_limit);
 			if (k < 0 || k >= at->values.size()) {
 			if (k < 0 || k >= at->values.size()) {
 				return -1;
 				return -1;
 			}
 			}
@@ -1659,7 +1659,7 @@ int Animation::track_find_key(int p_track, double p_time, FindMode p_find_mode,
 		} break;
 		} break;
 		case TYPE_ANIMATION: {
 		case TYPE_ANIMATION: {
 			AnimationTrack *at = static_cast<AnimationTrack *>(t);
 			AnimationTrack *at = static_cast<AnimationTrack *>(t);
-			int k = _find(at->values, p_time, false, p_limit);
+			int k = _find(at->values, p_time, p_backward, p_limit);
 			if (k < 0 || k >= at->values.size()) {
 			if (k < 0 || k >= at->values.size()) {
 				return -1;
 				return -1;
 			}
 			}
@@ -3836,7 +3836,7 @@ void Animation::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("track_get_key_count", "track_idx"), &Animation::track_get_key_count);
 	ClassDB::bind_method(D_METHOD("track_get_key_count", "track_idx"), &Animation::track_get_key_count);
 	ClassDB::bind_method(D_METHOD("track_get_key_value", "track_idx", "key_idx"), &Animation::track_get_key_value);
 	ClassDB::bind_method(D_METHOD("track_get_key_value", "track_idx", "key_idx"), &Animation::track_get_key_value);
 	ClassDB::bind_method(D_METHOD("track_get_key_time", "track_idx", "key_idx"), &Animation::track_get_key_time);
 	ClassDB::bind_method(D_METHOD("track_get_key_time", "track_idx", "key_idx"), &Animation::track_get_key_time);
-	ClassDB::bind_method(D_METHOD("track_find_key", "track_idx", "time", "find_mode", "limit"), &Animation::track_find_key, DEFVAL(FIND_MODE_NEAREST), DEFVAL(false));
+	ClassDB::bind_method(D_METHOD("track_find_key", "track_idx", "time", "find_mode", "limit", "backward"), &Animation::track_find_key, DEFVAL(FIND_MODE_NEAREST), DEFVAL(false), DEFVAL(false));
 
 
 	ClassDB::bind_method(D_METHOD("track_set_interpolation_type", "track_idx", "interpolation"), &Animation::track_set_interpolation_type);
 	ClassDB::bind_method(D_METHOD("track_set_interpolation_type", "track_idx", "interpolation"), &Animation::track_set_interpolation_type);
 	ClassDB::bind_method(D_METHOD("track_get_interpolation_type", "track_idx"), &Animation::track_get_interpolation_type);
 	ClassDB::bind_method(D_METHOD("track_get_interpolation_type", "track_idx"), &Animation::track_get_interpolation_type);

+ 2 - 2
scene/resources/animation.h

@@ -388,7 +388,7 @@ protected:
 	Vector3 _scale_track_interpolate_bind_compat_86629(int p_track, double p_time) const;
 	Vector3 _scale_track_interpolate_bind_compat_86629(int p_track, double p_time) const;
 	float _blend_shape_track_interpolate_bind_compat_86629(int p_track, double p_time) const;
 	float _blend_shape_track_interpolate_bind_compat_86629(int p_track, double p_time) const;
 	Variant _value_track_interpolate_bind_compat_86629(int p_track, double p_time) const;
 	Variant _value_track_interpolate_bind_compat_86629(int p_track, double p_time) const;
-	int _track_find_key_bind_compat_86661(int p_track, double p_time, FindMode p_find_mode = FIND_MODE_NEAREST) const;
+	int _track_find_key_bind_compat_92861(int p_track, double p_time, FindMode p_find_mode = FIND_MODE_NEAREST) const;
 	static void _bind_compatibility_methods();
 	static void _bind_compatibility_methods();
 #endif // DISABLE_DEPRECATED
 #endif // DISABLE_DEPRECATED
 
 
@@ -423,7 +423,7 @@ public:
 	void track_set_key_transition(int p_track, int p_key_idx, real_t p_transition);
 	void track_set_key_transition(int p_track, int p_key_idx, real_t p_transition);
 	void track_set_key_value(int p_track, int p_key_idx, const Variant &p_value);
 	void track_set_key_value(int p_track, int p_key_idx, const Variant &p_value);
 	void track_set_key_time(int p_track, int p_key_idx, double p_time);
 	void track_set_key_time(int p_track, int p_key_idx, double p_time);
-	int track_find_key(int p_track, double p_time, FindMode p_find_mode = FIND_MODE_NEAREST, bool p_limit = false) const;
+	int track_find_key(int p_track, double p_time, FindMode p_find_mode = FIND_MODE_NEAREST, bool p_limit = false, bool p_backward = false) const;
 	void track_remove_key(int p_track, int p_idx);
 	void track_remove_key(int p_track, int p_idx);
 	void track_remove_key_at_time(int p_track, double p_time);
 	void track_remove_key_at_time(int p_track, double p_time);
 	int track_get_key_count(int p_track) const;
 	int track_get_key_count(int p_track) const;