< Summary

Class:DCL.Components.DCLAnimator
Assembly:DCL.Components.Animation
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Animator/DCLAnimator.cs
Covered lines:75
Uncovered lines:31
Coverable lines:106
Total lines:250
Line coverage:70.7% (75 of 106)
Covered branches:0
Total branches:0
Covered methods:16
Total methods:19
Method coverage:84.2% (16 of 19)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
DCLAnimationState()0%110100%
Clone()0%2100%
GetDataFromJSON(...)0%110100%
GetDataFromPb(...)0%1321100%
DCLAnimator()0%110100%
Awake()0%110100%
OnDestroy()0%3.333066.67%
Cleanup()0%110100%
ApplyChanges(...)0%220100%
GetModel()0%110100%
IsEntityShapeLoaded()0%220100%
OnEntityShapeLoaded(...)0%9.386054.55%
OnShapeLoaded(...)0%2100%
Initialize()0%7.017095.24%
UpdateAnimationState()0%12.0912091.3%
ResetAnimation(...)0%3.333066.67%
GetStateByString(...)0%3.033085.71%
GetClassId()0%110100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Animator/DCLAnimator.cs

#LineLine coverage
 1using DCL.Models;
 2using System.Collections;
 3using System.Collections.Generic;
 4using DCL.Helpers;
 5using UnityEngine;
 6using Decentraland.Sdk.Ecs6;
 7
 8namespace DCL.Components
 9{
 10    public class DCLAnimator : BaseComponent
 11    {
 12        [System.Serializable]
 13        public class Model : BaseModel
 14        {
 15            [System.Serializable]
 16            public class DCLAnimationState
 17            {
 18                public string name;
 19                public string clip;
 20                public AnimationClip clipReference;
 21                public bool playing;
 22
 23                [Range(0, 1)]
 2224                public float weight = 1f;
 25
 2226                public float speed = 1f;
 2227                public bool looping = true;
 28                public bool shouldReset = false;
 29
 30                public DCLAnimationState Clone() =>
 031                    (DCLAnimationState) this.MemberwiseClone();
 32            }
 33
 34            public DCLAnimationState[] states;
 35
 36            public override BaseModel GetDataFromJSON(string json) =>
 1337                Utils.SafeFromJson<Model>(json);
 38
 39            public override BaseModel GetDataFromPb(ComponentBodyPayload pbModel)
 40            {
 041                if (pbModel.PayloadCase != ComponentBodyPayload.PayloadOneofCase.Animator)
 042                    return Utils.SafeUnimplemented<DCLAnimator, Model>(expected: ComponentBodyPayload.PayloadOneofCase.A
 43
 044                if (pbModel.Animator.States.Count == 0)
 045                    return new Model();
 46
 047                var model = new Model { states = new DCLAnimationState[pbModel.Animator.States.Count] };
 48
 049                for (var i = 0; i < pbModel.Animator.States.Count; i++)
 50                {
 051                    model.states[i] = new DCLAnimationState();
 52
 053                    if (pbModel.Animator.States[i].HasName) model.states[i].name = pbModel.Animator.States[i].Name;
 054                    if (pbModel.Animator.States[i].HasClip) model.states[i].clip = pbModel.Animator.States[i].Clip;
 055                    if (pbModel.Animator.States[i].HasPlaying) model.states[i].playing = pbModel.Animator.States[i].Play
 056                    if (pbModel.Animator.States[i].HasWeight) model.states[i].weight = pbModel.Animator.States[i].Weight
 057                    if (pbModel.Animator.States[i].HasSpeed) model.states[i].speed = pbModel.Animator.States[i].Speed;
 058                    if (pbModel.Animator.States[i].HasLooping) model.states[i].looping = pbModel.Animator.States[i].Loop
 059                    if (pbModel.Animator.States[i].HasShouldReset) model.states[i].shouldReset = pbModel.Animator.States
 60                }
 61
 062                return model;
 63            }
 64        }
 65
 66        [System.NonSerialized]
 67        public Animation animComponent = null;
 68
 69        private string lastLoadedModelSrc;
 70
 1171        Dictionary<string, AnimationClip> clipNameToClip = new Dictionary<string, AnimationClip>();
 1172        Dictionary<AnimationClip, AnimationState> clipToState = new Dictionary<AnimationClip, AnimationState>();
 73
 574        public override string componentName => "animator";
 75
 76        private void Awake()
 77        {
 878            model = new Model();
 879        }
 80
 81        private void OnDestroy()
 82        {
 883            if (entity == null) return;
 84
 885            entity.OnShapeLoaded -= OnEntityShapeLoaded;
 86
 887            if (scene.componentsManagerLegacy.GetSharedComponent(entity, typeof(BaseShape)) is LoadableShape animationSh
 088                animationShape.OnLoaded -= OnShapeLoaded;
 889        }
 90
 91        public override void Cleanup()
 92        {
 893            base.Cleanup();
 894            animComponent = null;
 895        }
 96
 97        public override IEnumerator ApplyChanges(BaseModel model)
 98        {
 1399            entity.OnShapeLoaded -= OnEntityShapeLoaded;
 13100            entity.OnShapeLoaded += OnEntityShapeLoaded;
 101
 102            //Note: If the entity is still loading the Shape, We wait until it is fully loaded to init it
 103            //      If we don't wait, this can cause an issue with the asset bundles not loadings animations
 104
 13105            if (IsEntityShapeLoaded())
 5106                UpdateAnimationState();
 107
 13108            return null;
 109        }
 110
 111        public new Model GetModel() =>
 1112            (Model) model;
 113
 114        private bool IsEntityShapeLoaded() =>
 13115            (scene.componentsManagerLegacy.GetSharedComponent(entity, typeof(BaseShape)) as LoadableShape)
 116            is { isLoaded: true };
 117
 118        private void OnEntityShapeLoaded(IDCLEntity shapeEntity)
 119        {
 5120            var animationShape = scene.componentsManagerLegacy.GetSharedComponent(entity, (typeof(BaseShape))) as Loadab
 121
 5122            if (animationShape?.GetModel() is not LoadableShape.Model shapeModel)
 0123                return;
 124
 5125            if ( shapeModel.src == lastLoadedModelSrc )
 0126                return;
 127
 5128            lastLoadedModelSrc = shapeModel.src;
 129
 5130            if (animationShape.isLoaded)
 131            {
 5132                UpdateAnimationState();
 133            }
 134            else
 135            {
 0136                animationShape.OnLoaded -= OnShapeLoaded;
 0137                animationShape.OnLoaded += OnShapeLoaded;
 138            }
 0139        }
 140
 141        private void OnShapeLoaded(LoadableShape shape)
 142        {
 0143            shape.OnLoaded -= OnShapeLoaded;
 0144            UpdateAnimationState();
 0145        }
 146
 147        private void Initialize()
 148        {
 10149            if (entity == null || animComponent != null)
 4150                return;
 151
 152            //NOTE(Brian): fetch all the AnimationClips in Animation component.
 6153            animComponent = transform.parent.GetComponentInChildren<Animation>(true);
 154
 6155            if (animComponent == null)
 0156                return;
 157
 6158            clipNameToClip.Clear();
 6159            clipToState.Clear();
 6160            int layerIndex = 0;
 161
 6162            animComponent.playAutomatically = true;
 6163            animComponent.enabled = true;
 6164            animComponent.Stop(); //NOTE(Brian): When the GLTF is created by GLTFSceneImporter a frame may be elapsed,
 165            //putting the component in play state if playAutomatically was true at that point.
 6166            animComponent.clip?.SampleAnimation(animComponent.gameObject, 0);
 167
 28168            foreach (AnimationState unityState in animComponent)
 169            {
 8170                clipNameToClip[unityState.clip.name] = unityState.clip;
 171
 8172                unityState.clip.wrapMode = WrapMode.Loop;
 8173                unityState.layer = layerIndex;
 8174                unityState.blendMode = AnimationBlendMode.Blend;
 8175                layerIndex++;
 176            }
 6177        }
 178
 179        void UpdateAnimationState()
 180        {
 10181            Initialize();
 182
 10183            if (clipNameToClip.Count == 0 || animComponent == null)
 0184                return;
 185
 10186            Model model = (Model) this.model;
 187
 10188            if (model.states == null || model.states.Length == 0)
 0189                return;
 190
 48191            for (int i = 0; i < model.states.Length; i++)
 192            {
 14193                Model.DCLAnimationState state = model.states[i];
 194
 14195                if (clipNameToClip.ContainsKey(state.clip))
 196                {
 14197                    AnimationState unityState = animComponent[state.clip];
 14198                    unityState.weight = state.weight;
 14199                    unityState.wrapMode = state.looping ? WrapMode.Loop : WrapMode.Default;
 14200                    unityState.clip.wrapMode = unityState.wrapMode;
 14201                    unityState.speed = state.speed;
 202
 14203                    state.clipReference = unityState.clip;
 204
 14205                    unityState.enabled = state.playing;
 206
 14207                    if (state.shouldReset)
 3208                        ResetAnimation(state);
 209
 210
 14211                    if (state.playing && !animComponent.IsPlaying(state.clip))
 212                    {
 3213                        animComponent.Play(state.clip);
 214                    }
 215                }
 216            }
 10217        }
 218
 219        public void ResetAnimation(Model.DCLAnimationState state)
 220        {
 4221            if (state == null || state.clipReference == null)
 222            {
 0223                Debug.LogError("Clip not found");
 0224                return;
 225            }
 226
 4227            animComponent.Stop(state.clip);
 228
 229            //Manually sample the animation. If the reset is not played again the frame 0 wont be applied
 4230            state.clipReference.SampleAnimation(animComponent.gameObject, 0);
 4231        }
 232
 233        public Model.DCLAnimationState GetStateByString(string stateName)
 234        {
 4235            Model model = (Model) this.model;
 236
 14237            for (var i = 0; i < model.states.Length; i++)
 238            {
 7239                if (model.states[i].name == stateName)
 240                {
 4241                    return model.states[i];
 242                }
 243            }
 244
 0245            return null;
 246        }
 247
 1248        public override int GetClassId() { return (int) CLASS_ID_COMPONENT.ANIMATOR; }
 249    }
 250}