| | 1 | | using System; |
| | 2 | | using System.Collections.Generic; |
| | 3 | | using DCL.Components; |
| | 4 | | using DCL.Controllers; |
| | 5 | | using DCL.ECSRuntime; |
| | 6 | | using DCL.Models; |
| | 7 | | using DCL.ECSComponents; |
| | 8 | | using UnityEngine; |
| | 9 | |
|
| | 10 | | namespace DCL.ECSComponents |
| | 11 | | { |
| | 12 | | public class AnimatorComponentHandler : IECSComponentHandler<PBAnimator> |
| | 13 | | { |
| | 14 | | private readonly DataStore_ECS7 dataStore; |
| | 15 | | private IDCLEntity entity; |
| | 16 | | private PBAnimator model; |
| | 17 | | internal Animation animComponent; |
| | 18 | | internal bool isShapeLoaded = false; |
| | 19 | |
|
| 5 | 20 | | internal Dictionary<string, AnimationClip> clipNameToClip = new Dictionary<string, AnimationClip>(); |
| | 21 | |
|
| 15 | 22 | | public AnimatorComponentHandler(DataStore_ECS7 dataStoreEcs7) { dataStore = dataStoreEcs7; } |
| | 23 | |
|
| 0 | 24 | | public void OnComponentCreated(IParcelScene scene, IDCLEntity entity) { } |
| | 25 | |
|
| | 26 | | public void OnComponentRemoved(IParcelScene scene, IDCLEntity entity) |
| | 27 | | { |
| 5 | 28 | | dataStore.shapesReady.OnAdded -= ShapeReadyAdded; |
| 5 | 29 | | } |
| | 30 | |
|
| | 31 | | public void OnComponentModelUpdated(IParcelScene scene, IDCLEntity entity, PBAnimator model) |
| | 32 | | { |
| 1 | 33 | | this.entity = entity; |
| 1 | 34 | | this.model = model; |
| | 35 | |
|
| | 36 | | // If shape is loaded we just update the state of the animation with the model info |
| 1 | 37 | | if (isShapeLoaded) |
| | 38 | | { |
| 0 | 39 | | UpdateAnimationState(model); |
| 0 | 40 | | } |
| | 41 | | else |
| | 42 | | { |
| | 43 | | // If shape is not loaded, we check if it is already loaded, if not we subscribe to when it is ready |
| 1 | 44 | | if (dataStore.shapesReady.TryGetValue(entity.entityId, out GameObject gameObject)) |
| | 45 | | { |
| 0 | 46 | | ShapeReadyAdded(entity.entityId, gameObject); |
| 0 | 47 | | } |
| | 48 | | else |
| | 49 | | { |
| 1 | 50 | | dataStore.shapesReady.OnAdded -= ShapeReadyAdded; |
| 1 | 51 | | dataStore.shapesReady.OnAdded += ShapeReadyAdded; |
| | 52 | | } |
| | 53 | | } |
| 1 | 54 | | } |
| | 55 | |
|
| | 56 | | private void ShapeReadyAdded(long entityId, GameObject gameObject) |
| | 57 | | { |
| 1 | 58 | | if (entityId != entity.entityId) |
| 0 | 59 | | return; |
| | 60 | |
|
| 1 | 61 | | Initialize(entity); |
| 1 | 62 | | isShapeLoaded = true; |
| | 63 | |
|
| 1 | 64 | | UpdateAnimationState(model); |
| 1 | 65 | | } |
| | 66 | |
|
| | 67 | | internal void Initialize(IDCLEntity entity) |
| | 68 | | { |
| 3 | 69 | | if (entity == null) |
| 0 | 70 | | return; |
| | 71 | |
|
| | 72 | | //NOTE(Brian): fetch all the AnimationClips in Animation component. |
| 3 | 73 | | animComponent = entity.gameObject.GetComponentInChildren<Animation>(true); |
| | 74 | |
|
| 3 | 75 | | if (animComponent == null) |
| 0 | 76 | | return; |
| | 77 | |
|
| 3 | 78 | | clipNameToClip.Clear(); |
| 3 | 79 | | int layerIndex = 0; |
| | 80 | |
|
| 3 | 81 | | animComponent.playAutomatically = true; |
| 3 | 82 | | animComponent.enabled = true; |
| 3 | 83 | | animComponent.Stop(); //NOTE(Brian): When the GLTF is created by GLTFSceneImporter a frame may be elapsed, |
| | 84 | | //putting the component in play state if playAutomatically was true at that point. |
| 3 | 85 | | animComponent.clip?.SampleAnimation(animComponent.gameObject, 0); |
| | 86 | |
|
| 6 | 87 | | foreach (AnimationState unityState in animComponent) |
| | 88 | | { |
| 0 | 89 | | clipNameToClip[unityState.clip.name] = unityState.clip; |
| | 90 | |
|
| 0 | 91 | | unityState.clip.wrapMode = WrapMode.Loop; |
| 0 | 92 | | unityState.layer = layerIndex; |
| 0 | 93 | | unityState.blendMode = AnimationBlendMode.Blend; |
| 0 | 94 | | layerIndex++; |
| | 95 | | } |
| 3 | 96 | | } |
| | 97 | |
|
| | 98 | | internal void UpdateAnimationState(PBAnimator model) |
| | 99 | | { |
| 1 | 100 | | if (clipNameToClip.Count == 0 || animComponent == null) |
| 1 | 101 | | return; |
| | 102 | |
|
| 0 | 103 | | if (model.States.Count == 0) |
| 0 | 104 | | return; |
| | 105 | |
|
| 0 | 106 | | for (int i = 0; i < model.States.Count; i++) |
| | 107 | | { |
| 0 | 108 | | if (clipNameToClip.ContainsKey(model.States[i].Clip)) |
| | 109 | | { |
| 0 | 110 | | AnimationState unityState = animComponent[model.States[i].Clip]; |
| 0 | 111 | | unityState.weight = model.States[i].GetWeight(); |
| | 112 | |
|
| 0 | 113 | | unityState.wrapMode = model.States[i].GetLoop() ? WrapMode.Loop : WrapMode.Default; |
| | 114 | |
|
| 0 | 115 | | unityState.clip.wrapMode = unityState.wrapMode; |
| 0 | 116 | | unityState.speed = model.States[i].GetSpeed(); |
| 0 | 117 | | unityState.enabled = model.States[i].Playing; |
| | 118 | |
|
| 0 | 119 | | if (model.States[i].ShouldReset) |
| 0 | 120 | | ResetAnimation(model.States[i], unityState.clip); |
| | 121 | |
|
| 0 | 122 | | if (model.States[i].Playing && !animComponent.IsPlaying(model.States[i].Clip)) |
| 0 | 123 | | animComponent.Play(model.States[i].Clip); |
| | 124 | | } |
| | 125 | | } |
| 0 | 126 | | } |
| | 127 | |
|
| | 128 | | private void ResetAnimation(PBAnimationState state, AnimationClip clipReference) |
| | 129 | | { |
| 0 | 130 | | if (state == null || clipReference == null) |
| | 131 | | { |
| 0 | 132 | | Debug.LogError("Clip not found"); |
| 0 | 133 | | return; |
| | 134 | | } |
| | 135 | |
|
| 0 | 136 | | animComponent.Stop(state.Clip); |
| | 137 | |
|
| | 138 | | //Manually sample the animation. If the reset is not played again the frame 0 wont be applied |
| 0 | 139 | | clipReference.SampleAnimation(animComponent.gameObject, 0); |
| 0 | 140 | | } |
| | 141 | | } |
| | 142 | | } |