1- import type { AnimationClip } from 'cc' ;
1+ import type { AnimationClip , Asset } from 'cc' ;
22import type {
33 IAnimationAuxiliaryCurveDump ,
44 IAnimationCurveDump ,
5+ IAnimationCurveKeyDump ,
56 IAnimationEmbeddedPlayerDump ,
67 IAnimationEmbeddedPlayerGroup ,
78 IAnimationEventDump ,
9+ IAnimationValue ,
810} from '../../../common' ;
11+ import {
12+ loadAnimationAssetValue ,
13+ queryAnimationAssetCtor ,
14+ queryAnimationAssetUuid ,
15+ } from './asset-value' ;
916import { dumpAuxiliaryCurves , replaceAuxiliaryCurves } from './auxiliary-curve' ;
1017import {
1118 dumpEmbeddedPlayers ,
@@ -34,6 +41,9 @@ export interface IAnimationClipSnapshot {
3441 auxiliaryCurves : Record < string , IAnimationAuxiliaryCurveDump > ;
3542}
3643
44+ type AnimationAssetCtor = new ( ) => Asset ;
45+ type PendingAnimationAssetLoads = Map < AnimationAssetCtor , Map < string , Promise < Asset > > > ;
46+
3747export function captureAnimationClipSnapshot ( clip : AnimationClip , options : IPropertyCurveMetadataContext = { } ) : IAnimationClipSnapshot {
3848 const sample = getClipSample ( clip ) ;
3949 const events = queryClipEvents ( clip ) || [ ] ;
@@ -56,24 +66,30 @@ export function captureAnimationClipSnapshot(clip: AnimationClip, options: IProp
5666
5767export async function restoreAnimationClipSnapshot ( clip : AnimationClip , snapshot : IAnimationClipSnapshot ) : Promise < void > {
5868 const previous = captureAnimationClipSnapshot ( clip ) ;
69+ const pendingAssetLoads : PendingAnimationAssetLoads = new Map ( ) ;
5970 try {
60- await applyAnimationClipSnapshot ( clip , snapshot ) ;
71+ await applyAnimationClipSnapshot ( clip , snapshot , pendingAssetLoads ) ;
6172 } catch ( error ) {
6273 try {
63- await applyAnimationClipSnapshot ( clip , previous ) ;
74+ await applyAnimationClipSnapshot ( clip , previous , pendingAssetLoads ) ;
6475 } catch ( restoreError ) {
6576 console . error ( '[Animation] rollback failed animation clip snapshot restore:' , restoreError ) ;
6677 }
6778 throw error ;
6879 }
6980}
7081
71- async function applyAnimationClipSnapshot ( clip : AnimationClip , snapshot : IAnimationClipSnapshot ) : Promise < void > {
82+ async function applyAnimationClipSnapshot (
83+ clip : AnimationClip ,
84+ snapshot : IAnimationClipSnapshot ,
85+ pendingAssetLoads : PendingAnimationAssetLoads ,
86+ ) : Promise < void > {
7287 ( clip as any ) . duration = snapshot . duration ;
7388 ( clip as any ) . sample = snapshot . sample ;
7489 ( clip as any ) . speed = snapshot . speed ;
7590 ( clip as any ) . wrapMode = snapshot . wrapMode ;
76- if ( ! replacePropertyCurves ( clip , snapshot . curves ) ) {
91+ const curves = await hydrateAnimationAssetCurveValues ( snapshot . curves , pendingAssetLoads ) ;
92+ if ( ! replacePropertyCurves ( clip , curves ) ) {
7793 throw new Error ( 'Failed to restore animation property curves.' ) ;
7894 }
7995 restoreEvents ( clip , snapshot ) ;
@@ -86,6 +102,86 @@ async function applyAnimationClipSnapshot(clip: AnimationClip, snapshot: IAnimat
86102 }
87103}
88104
105+ async function hydrateAnimationAssetCurveValues (
106+ curves : IAnimationCurveDump [ ] ,
107+ pendingAssetLoads : PendingAnimationAssetLoads ,
108+ ) : Promise < IAnimationCurveDump [ ] > {
109+ return await Promise . all ( curves . map ( async ( curve ) => {
110+ if ( ! Array . isArray ( curve . keyframes ) || curve . keyframes . length === 0 ) {
111+ return curve ;
112+ }
113+
114+ let changed = false ;
115+ const keyframes = await Promise . all ( curve . keyframes . map ( async ( keyframe ) => {
116+ const value = await hydrateAnimationAssetKeyframeValue ( curve , keyframe , pendingAssetLoads ) ;
117+ if ( value === keyframe . dump . value ) {
118+ return keyframe ;
119+ }
120+ changed = true ;
121+ return {
122+ ...keyframe ,
123+ dump : {
124+ ...keyframe . dump ,
125+ value : value as IAnimationValue ,
126+ } ,
127+ } ;
128+ } ) ) ;
129+
130+ return changed ? { ...curve , keyframes } : curve ;
131+ } ) ) ;
132+ }
133+
134+ async function hydrateAnimationAssetKeyframeValue (
135+ curve : IAnimationCurveDump ,
136+ keyframe : IAnimationCurveKeyDump ,
137+ pendingAssetLoads : PendingAnimationAssetLoads ,
138+ ) : Promise < unknown > {
139+ const assetCtor = queryAnimationAssetKeyframeCtor ( curve , keyframe ) ;
140+ const value = keyframe . dump . value as unknown ;
141+ if ( ! assetCtor || value === null || value === undefined || value instanceof assetCtor ) {
142+ return value ;
143+ }
144+
145+ const uuid = queryAnimationAssetUuid ( value ) ;
146+ if ( ! uuid ) {
147+ return value ;
148+ }
149+
150+ return await loadAnimationAssetOnce ( assetCtor , uuid , pendingAssetLoads ) ;
151+ }
152+
153+ function queryAnimationAssetKeyframeCtor (
154+ curve : IAnimationCurveDump ,
155+ keyframe : IAnimationCurveKeyDump ,
156+ ) : AnimationAssetCtor | null {
157+ if ( keyframe . dump . type ) {
158+ const keyframeCtor = queryAnimationAssetCtor ( { type : { value : keyframe . dump . type } } ) ;
159+ if ( keyframeCtor ) {
160+ return keyframeCtor ;
161+ }
162+ }
163+ return curve . type ? queryAnimationAssetCtor ( { type : curve . type } ) : null ;
164+ }
165+
166+ function loadAnimationAssetOnce (
167+ assetCtor : AnimationAssetCtor ,
168+ uuid : string ,
169+ pendingAssetLoads : PendingAnimationAssetLoads ,
170+ ) : Promise < Asset > {
171+ let ctorLoads = pendingAssetLoads . get ( assetCtor ) ;
172+ if ( ! ctorLoads ) {
173+ ctorLoads = new Map ( ) ;
174+ pendingAssetLoads . set ( assetCtor , ctorLoads ) ;
175+ }
176+
177+ let pending = ctorLoads . get ( uuid ) ;
178+ if ( ! pending ) {
179+ pending = loadAnimationAssetValue ( assetCtor , uuid ) ;
180+ ctorLoads . set ( uuid , pending ) ;
181+ }
182+ return pending ;
183+ }
184+
89185export function animationClipSnapshotsEqual ( left : IAnimationClipSnapshot , right : IAnimationClipSnapshot ) : boolean {
90186 return JSON . stringify ( left ) === JSON . stringify ( right ) ;
91187}
0 commit comments