extends Node3D ## Merges every animation in the AnimationPlayer into a single looping clip and ## plays it, so meshes driven by different animations (e.g. ted_bones and ## fishing_acc) all animate simultaneously instead of overwriting each other. ## Attach to any node that has an AnimationPlayer child. @onready var anim_player: AnimationPlayer = $AnimationPlayer const MERGED_LIB := "merged" const MERGED_NAME := "merged/all" func _ready() -> void: if not anim_player: push_warning("tekton_fishing_autoplay: No AnimationPlayer found") return # Wait one frame for the scene tree to settle await get_tree().process_frame var source_names := anim_player.get_animation_list() if source_names.is_empty(): return var merged := _build_merged_animation(source_names) if not merged: return var lib := AnimationLibrary.new() lib.add_animation("all", merged) if anim_player.has_animation_library(MERGED_LIB): anim_player.remove_animation_library(MERGED_LIB) anim_player.add_animation_library(MERGED_LIB, lib) anim_player.play(MERGED_NAME) ## Combines the tracks of every source animation into one Animation. The source ## animations target disjoint node sets, so simply concatenating their tracks ## drives all meshes at once. func _build_merged_animation(source_names: Array) -> Animation: var merged := Animation.new() merged.loop_mode = Animation.LOOP_LINEAR var max_length := 0.0 for anim_name in source_names: var src: Animation = anim_player.get_animation(anim_name) if not src: continue max_length = max(max_length, src.length) for t in src.get_track_count(): _copy_track(src, t, merged) merged.length = max_length return merged func _copy_track(src: Animation, src_track: int, dst: Animation) -> void: var new_track := dst.add_track(src.track_get_type(src_track)) dst.track_set_path(new_track, src.track_get_path(src_track)) dst.track_set_interpolation_type(new_track, src.track_get_interpolation_type(src_track)) dst.track_set_interpolation_loop_wrap(new_track, src.track_get_interpolation_loop_wrap(src_track)) dst.track_set_enabled(new_track, src.track_is_enabled(src_track)) for k in src.track_get_key_count(src_track): var time := src.track_get_key_time(src_track, k) var value = src.track_get_key_value(src_track, k) var transition := src.track_get_key_transition(src_track, k) dst.track_insert_key(new_track, time, value, transition)