Key compiled animation clip cache by identity, not asset name - #1220
Conversation
Independently exported clips can share the same asset-embedded name (e.g. a default Blender action name), which caused the compiled-pose cache to collide and silently serve one clip's compiled data for another after changeAnimation switched to it.
|
Identity keys are the right fix. Two things worth closing while you're in there, plus one nice-to-have. 1. Stale entries can outlive their clip. var animationClips: [String: AnimationClip] = [:] {
didSet {
let live = Set(animationClips.values.map(ObjectIdentifier.init))
compiledClips = compiledClips.filter { live.contains($0.key) }
}
}
2. No regression test. Nice-to-have: the For the record, the CoolZombie clips are unaffected (each exported action is named after its clip), so this only bites assets whose actions kept a default name. |
registerRuntimeAnimationClips overwrites animationClips[name] directly rather than going through removeAnimationClip, so replacing a clip (re-registration, reload, or a duplicate embedded name) freed the old AnimationClip while its ObjectIdentifier-keyed compiledClips entry stayed behind. CompiledAnimationClip holds no reference back to its source clip, so if Swift reused the freed address for a later clip, the stale entry could be served as that clip's compiled data. Add a didSet on animationClips that prunes any compiledClips entry whose key is no longer live, covering every mutation path instead of only the removeAnimationClip case. Also have the preferredName alias reuse the AnimationClip instance registered under the clip's own name instead of allocating a second one, since identity-keyed compilation would otherwise compile the same data twice.
Summary
AnimationComponent.compiledClip(for:)cached compiled pose data keyed byAnimationClip.name, which comes from the asset file (e.g. the source Blender action name), not the lookup name passed tosetEntityAnimations/changeAnimation.idleandrunning) commonly share the same embedded name, so the second clip's compiled data collided with the first's cache entry —changeAnimationcorrectly swappedcurrentAnimation, but playback stayed on the previously cached clip.compiledClipsonObjectIdentifier(clip)instead of the name, so the cache is correct regardless of what name the source asset embeds.removeAnimationClipupdated to match.Test plan
swift buildswift test --filter AnimationCompiledSamplerTests(12/12 passing, including compiled-vs-legacy parity and the sampling performance baseline)