When the update of a PlayableDirector happens during the execution order?

tl;dr:
Before the frame ends, After the Evaluation/Update of a PlayableDirector, I wanna run my animation logic. But I can't seem to find the right timing, and manually updating PlayableDirectors isn't an option.

The question:
We created a cutscene system using Timeline and PlayableDirector. Some of the custom tracks in our cutscenes require our animation logic updates, because they do not directly set clips for their Animators.

Initially, we tried manually updating the PlayableDirectors to have more control over them, but we quickly switched to using the GameTime method for updates.

However, this change caused the one-frame lag problem, because the PlayableDirector's update occurred after the Update() timing, so we couldn't apply the output of the timeline tracks to the Animators.

We are now trying to find the right timing in the execution order to insert our animation logic code. Does anyone know how the PlayableDirector works internally and can help us with this issue? Thank you in advance.

Hello,
You can dump the contents of PlayerLoop to see where the PlayableDirector's update occurs.
https://docs.unity3d.com/ScriptReference/LowLevel.PlayerLoop.GetCurrentPlayerLoop.html
BTW the following result is what I've dumped ago, and I thought the "DirectorDeferredEvaluate" is when the timeline and its animation executes. You can also inject your custom player loop function to make sure its execute before or after PlayableDirector's update.
Another faster solution is just add your task to LateUpdate.

0 --->> loop UnityEngine.PlayerLoop.TimeUpdate
0 loop UnityEngine.PlayerLoop.TimeUpdate+WaitForLastPresentationAndUpdateTime
1 --->> loop UnityEngine.PlayerLoop.Initialization
0 loop UnityEngine.PlayerLoop.Initialization+UpdateCameraMotionVectors
1 loop UnityEngine.PlayerLoop.Initialization+DirectorSampleTime
2 loop UnityEngine.PlayerLoop.Initialization+AsyncUploadTimeSlicedUpdate
3 loop UnityEngine.PlayerLoop.Initialization+SynchronizeInputs
4 loop UnityEngine.PlayerLoop.Initialization+SynchronizeState
5 loop UnityEngine.PlayerLoop.Initialization+XREarlyUpdate
2 --->> loop UnityEngine.PlayerLoop.EarlyUpdate
0 loop UnityEngine.PlayerLoop.EarlyUpdate+PollPlayerConnection
1 loop UnityEngine.PlayerLoop.EarlyUpdate+ProfilerStartFrame
2 loop UnityEngine.PlayerLoop.EarlyUpdate+GpuTimestamp
3 loop UnityEngine.PlayerLoop.EarlyUpdate+AnalyticsCoreStatsUpdate
4 loop UnityEngine.PlayerLoop.EarlyUpdate+UnityWebRequestUpdate
5 loop UnityEngine.PlayerLoop.EarlyUpdate+ExecuteMainThreadJobs
6 loop UnityEngine.PlayerLoop.EarlyUpdate+ProcessMouseInWindow
7 loop UnityEngine.PlayerLoop.EarlyUpdate+ClearIntermediateRenderers
8 loop UnityEngine.PlayerLoop.EarlyUpdate+ClearLines
9 loop UnityEngine.PlayerLoop.EarlyUpdate+PresentBeforeUpdate
10 loop UnityEngine.PlayerLoop.EarlyUpdate+ResetFrameStatsAfterPresent
11 loop UnityEngine.PlayerLoop.EarlyUpdate+UpdateAsyncReadbackManager
12 loop UnityEngine.PlayerLoop.EarlyUpdate+UpdateStreamingManager
13 loop UnityEngine.PlayerLoop.EarlyUpdate+UpdateTextureStreamingManager
14 loop UnityEngine.PlayerLoop.EarlyUpdate+UpdatePreloading
15 loop UnityEngine.PlayerLoop.EarlyUpdate+RendererNotifyInvisible
16 loop UnityEngine.PlayerLoop.EarlyUpdate+PlayerCleanupCachedData
17 loop UnityEngine.PlayerLoop.EarlyUpdate+UpdateMainGameViewRect
18 loop UnityEngine.PlayerLoop.EarlyUpdate+UpdateCanvasRectTransform
19 loop UnityEngine.PlayerLoop.EarlyUpdate+XRUpdate
20 loop UnityEngine.PlayerLoop.EarlyUpdate+UpdateInputManager
21 loop UnityEngine.PlayerLoop.EarlyUpdate+ProcessRemoteInput
22 loop UnityEngine.PlayerLoop.EarlyUpdate+ScriptRunDelayedStartupFrame
23 loop UnityEngine.PlayerLoop.EarlyUpdate+UpdateKinect
24 loop UnityEngine.PlayerLoop.EarlyUpdate+DeliverIosPlatformEvents
25 loop UnityEngine.PlayerLoop.EarlyUpdate+ARCoreUpdate
26 loop UnityEngine.PlayerLoop.EarlyUpdate+DispatchEventQueueEvents
27 loop UnityEngine.PlayerLoop.EarlyUpdate+PhysicsResetInterpolatedTransformPosition
28 loop UnityEngine.PlayerLoop.EarlyUpdate+SpriteAtlasManagerUpdate
29 loop UnityEngine.PlayerLoop.EarlyUpdate+PerformanceAnalyticsUpdate
3 --->> loop UnityEngine.PlayerLoop.FixedUpdate
0 loop UnityEngine.PlayerLoop.FixedUpdate+ClearLines
1 loop UnityEngine.PlayerLoop.FixedUpdate+NewInputFixedUpdate
2 loop UnityEngine.PlayerLoop.FixedUpdate+DirectorFixedSampleTime
3 loop UnityEngine.PlayerLoop.FixedUpdate+AudioFixedUpdate
4 loop UnityEngine.PlayerLoop.FixedUpdate+ScriptRunBehaviourFixedUpdate
5 loop UnityEngine.PlayerLoop.FixedUpdate+DirectorFixedUpdate
6 loop UnityEngine.PlayerLoop.FixedUpdate+LegacyFixedAnimationUpdate
7 loop UnityEngine.PlayerLoop.FixedUpdate+XRFixedUpdate
8 loop UnityEngine.PlayerLoop.FixedUpdate+PhysicsFixedUpdate
9 loop UnityEngine.PlayerLoop.FixedUpdate+Physics2DFixedUpdate
10 loop UnityEngine.PlayerLoop.FixedUpdate+PhysicsClothFixedUpdate
11 loop UnityEngine.PlayerLoop.FixedUpdate+DirectorFixedUpdatePostPhysics
12 loop UnityEngine.PlayerLoop.FixedUpdate+ScriptRunDelayedFixedFrameRate
4 --->> loop UnityEngine.PlayerLoop.PreUpdate
0 loop UnityEngine.PlayerLoop.PreUpdate+PhysicsUpdate
1 loop UnityEngine.PlayerLoop.PreUpdate+Physics2DUpdate
2 loop UnityEngine.PlayerLoop.PreUpdate+CheckTexFieldInput
3 loop UnityEngine.PlayerLoop.PreUpdate+IMGUISendQueuedEvents
4 loop UnityEngine.PlayerLoop.PreUpdate+NewInputUpdate
5 loop UnityEngine.PlayerLoop.PreUpdate+SendMouseEvents
6 loop UnityEngine.PlayerLoop.PreUpdate+AIUpdate
7 loop UnityEngine.PlayerLoop.PreUpdate+WindUpdate
8 loop UnityEngine.PlayerLoop.PreUpdate+UpdateVideo
5 --->> loop UnityEngine.PlayerLoop.Update
0 loop UnityEngine.PlayerLoop.Update+ScriptRunBehaviourUpdate
1 loop UnityEngine.PlayerLoop.Update+ScriptRunDelayedDynamicFrameRate
2 loop UnityEngine.PlayerLoop.Update+ScriptRunDelayedTasks
3 loop UnityEngine.PlayerLoop.Update+DirectorUpdate
6 --->> loop UnityEngine.PlayerLoop.PreLateUpdate
0 loop UnityEngine.PlayerLoop.PreLateUpdate+AIUpdatePostScript
1 loop UnityEngine.PlayerLoop.PreLateUpdate+DirectorUpdateAnimationBegin
2 loop UnityEngine.PlayerLoop.PreLateUpdate+LegacyAnimationUpdate
3 loop UnityEngine.PlayerLoop.PreLateUpdate+DirectorUpdateAnimationEnd
4 loop UnityEngine.PlayerLoop.PreLateUpdate+DirectorDeferredEvaluate <--- Timeline & Animation
5 loop UnityEngine.PlayerLoop.PreLateUpdate+UIElementsUpdatePanels
6 loop UnityEngine.PlayerLoop.PreLateUpdate+EndGraphicsJobsAfterScriptUpdate
7 loop UnityEngine.PlayerLoop.PreLateUpdate+ConstraintManagerUpdate
8 loop UnityEngine.PlayerLoop.PreLateUpdate+ParticleSystemBeginUpdateAll
9 loop UnityEngine.PlayerLoop.PreLateUpdate+Physics2DLateUpdate
10 loop UnityEngine.PlayerLoop.PreLateUpdate+ScriptRunBehaviourLateUpdate
7 --->> loop UnityEngine.PlayerLoop.PostLateUpdate
0 loop UnityEngine.PlayerLoop.PostLateUpdate+PlayerSendFrameStarted
1 loop UnityEngine.PlayerLoop.PostLateUpdate+DirectorLateUpdate
2 loop UnityEngine.PlayerLoop.PostLateUpdate+ScriptRunDelayedDynamicFrameRate
3 loop UnityEngine.PlayerLoop.PostLateUpdate+PhysicsSkinnedClothBeginUpdate
4 loop UnityEngine.PlayerLoop.PostLateUpdate+UpdateRectTransform
5 loop UnityEngine.PlayerLoop.PostLateUpdate+PlayerUpdateCanvases
6 loop UnityEngine.PlayerLoop.PostLateUpdate+UpdateAudio
7 loop UnityEngine.PlayerLoop.PostLateUpdate+VFXUpdate
8 loop UnityEngine.PlayerLoop.PostLateUpdate+ParticleSystemEndUpdateAll
9 loop UnityEngine.PlayerLoop.PostLateUpdate+EndGraphicsJobsAfterScriptLateUpdate
10 loop UnityEngine.PlayerLoop.PostLateUpdate+UpdateCustomRenderTextures
11 loop UnityEngine.PlayerLoop.PostLateUpdate+XRPostLateUpdate
12 loop UnityEngine.PlayerLoop.PostLateUpdate+UpdateAllRenderers
13 loop UnityEngine.PlayerLoop.PostLateUpdate+UpdateLightProbeProxyVolumes
14 loop UnityEngine.PlayerLoop.PostLateUpdate+EnlightenRuntimeUpdate
15 loop UnityEngine.PlayerLoop.PostLateUpdate+UpdateAllSkinnedMeshes
16 loop UnityEngine.PlayerLoop.PostLateUpdate+ProcessWebSendMessages
17 loop UnityEngine.PlayerLoop.PostLateUpdate+SortingGroupsUpdate
18 loop UnityEngine.PlayerLoop.PostLateUpdate+UpdateVideoTextures
19 loop UnityEngine.PlayerLoop.PostLateUpdate+UpdateVideo
20 loop UnityEngine.PlayerLoop.PostLateUpdate+DirectorRenderImage
21 loop UnityEngine.PlayerLoop.PostLateUpdate+PlayerEmitCanvasGeometry
22 loop UnityEngine.PlayerLoop.PostLateUpdate+PhysicsSkinnedClothFinishUpdate
23 loop UnityEngine.PlayerLoop.PostLateUpdate+FinishFrameRendering
24 loop UnityEngine.PlayerLoop.PostLateUpdate+BatchModeUpdate
25 loop UnityEngine.PlayerLoop.PostLateUpdate+PlayerSendFrameComplete
26 loop UnityEngine.PlayerLoop.PostLateUpdate+UpdateCaptureScreenshot
27 loop UnityEngine.PlayerLoop.PostLateUpdate+PresentAfterDraw
28 loop UnityEngine.PlayerLoop.PostLateUpdate+ClearImmediateRenderers
29 loop UnityEngine.PlayerLoop.PostLateUpdate+PlayerSendFramePostPresent
30 loop UnityEngine.PlayerLoop.PostLateUpdate+UpdateResolution
31 loop UnityEngine.PlayerLoop.PostLateUpdate+InputEndFrame
32 loop UnityEngine.PlayerLoop.PostLateUpdate+TriggerEndOfFrameCallbacks
33 loop UnityEngine.PlayerLoop.PostLateUpdate+GUIClearEvents
34 loop UnityEngine.PlayerLoop.PostLateUpdate+ShaderHandleErrors
35 loop UnityEngine.PlayerLoop.PostLateUpdate+ResetInputAxis
36 loop UnityEngine.PlayerLoop.PostLateUpdate+ThreadedLoadingDebug
37 loop UnityEngine.PlayerLoop.PostLateUpdate+ProfilerSynchronizeStats
38 loop UnityEngine.PlayerLoop.PostLateUpdate+MemoryFrameMaintenance
39 loop UnityEngine.PlayerLoop.PostLateUpdate+ExecuteGameCenterCallbacks
40 loop UnityEngine.PlayerLoop.PostLateUpdate+XRPreEndFrame
41 loop UnityEngine.PlayerLoop.PostLateUpdate+ProfilerEndFrame

This is just awesome. You saved a lot of my time. I gave it a shot if I could catch the right timing. In my case, attaching a delegate at the PreLateUpdate+DirectorDeferredEvaluate works. Thanks a lot.

@enghqii Would you mind sharing a little code snippet how you achived attaching the delegate? I'm only able to attach to PreLateUpdate but attaching to DirectorDeferredEvaluate doesn't seem to have an effect.

var playerLoop = PlayerLoop.GetCurrentPlayerLoop();
var preLateUpdateLoop = playerLoop.subSystemList[6];
var directorEvaluateLoop = preLateUpdateLoop.subSystemList[4];
preLateUpdateLoop.updateDelegate += PreLateUpdateDelegate; //works
directorEvaluateLoop.updateDelegate += DirectorEvaluateDelegate; //ignored
preLateUpdateLoop.subSystemList[4] = directorEvaluateLoop;
playerLoop.subSystemList[6] = preLateUpdateLoop;
PlayerLoop.SetPlayerLoop(playerLoop);