< Summary

Class:DCL.Components.LoadableShape[LoadWrapperType,LoadWrapperModelType]
Assembly:DCL.Components.LoadableShapes
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/LoadableShapes/LoadableShape.cs
Covered lines:95
Uncovered lines:35
Coverable lines:130
Total lines:352
Line coverage:73% (95 of 130)
Covered branches:0
Total branches:0
Covered methods:16
Total methods:18
Method coverage:88.8% (16 of 18)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
LoadableShape()0%110100%
ApplyChanges(...)0%11.0211095%
AttachShape(...)0%14.439059.38%
ConfigureVisibility(...)0%330100%
UpdateAnimationStatus(...)0%330100%
ConfigureColliders(...)0%220100%
OnLoadFailed(...)0%12300%
CleanFailedWrapper(...)0%20400%
OnLoadCompleted(...)0%4.044086.67%
OnInsideBoundariesChanged(...)0%110100%
DetachShape(...)0%4.024088.89%
CallWhenReady(...)0%440100%
RaiseOnShapeUpdated(...)0%330100%
RaiseOnShapeLoaded(...)0%3.143075%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/LoadableShapes/LoadableShape.cs

#LineLine coverage
 1using System;
 2using DCL.Helpers;
 3using DCL.Models;
 4using System.Collections;
 5using UnityEngine;
 6using Decentraland.Sdk.Ecs6;
 7
 8namespace DCL.Components
 9{
 10    public class LoadableShape : BaseShape, IAssetCatalogReferenceHolder
 11    {
 12        [Serializable]
 13        public new class Model : BaseShape.Model
 14        {
 15            public string src;
 16            public string assetId;
 17
 18            public override BaseModel GetDataFromJSON(string json) =>
 19                Utils.SafeFromJson<Model>(json);
 20
 21            public override BaseModel GetDataFromPb(ComponentBodyPayload pbModel)
 22            {
 23                switch (pbModel.PayloadCase)
 24                {
 25                    case ComponentBodyPayload.PayloadOneofCase.GltfShape:
 26                        var gltfModel = new Model();
 27                        if (pbModel.GltfShape.HasSrc) gltfModel.src = pbModel.GltfShape.Src;
 28                        if (pbModel.GltfShape.HasWithCollisions) gltfModel.withCollisions = pbModel.GltfShape.WithCollis
 29                        if (pbModel.GltfShape.HasVisible) gltfModel.visible = pbModel.GltfShape.Visible;
 30                        if (pbModel.GltfShape.HasIsPointerBlocker) gltfModel.isPointerBlocker = pbModel.GltfShape.IsPoin
 31
 32                        return gltfModel;
 33                    case ComponentBodyPayload.PayloadOneofCase.ObjShape:
 34                        var objModel = new Model();
 35                        if (pbModel.ObjShape.HasSrc) objModel.src = pbModel.ObjShape.Src;
 36                        if (pbModel.ObjShape.HasWithCollisions) objModel.withCollisions = pbModel.ObjShape.WithCollision
 37                        if (pbModel.ObjShape.HasVisible) objModel.visible = pbModel.ObjShape.Visible;
 38                        if (pbModel.ObjShape.HasIsPointerBlocker) objModel.isPointerBlocker = pbModel.ObjShape.IsPointer
 39
 40                        return objModel;
 41                    default:
 42                        return Utils.SafeUnimplemented<LoadableShape, Model>(
 43                            expected: ComponentBodyPayload.PayloadOneofCase.GltfShape, actual: pbModel.PayloadCase);
 44                }
 45            }
 46        }
 47
 48        public bool isLoaded { get; protected set; }
 49
 50        public Action<LoadableShape> OnLoaded;
 51
 52        protected Model previousModel = new ();
 53
 54        protected LoadableShape()
 55        {
 56            model = new Model();
 57        }
 58
 59        public override int GetClassId() =>
 60            -1;
 61
 62        public override IEnumerator ApplyChanges(BaseModel newModel) =>
 63            null;
 64
 65        public override bool IsVisible() =>
 66            ((Model)this.model).visible;
 67
 68        public override bool HasCollisions() =>
 69            ((Model)this.model).withCollisions;
 70
 71        public string GetAssetId() =>
 72            ((Model)this.model).assetId;
 73    }
 74
 75    public class LoadableShape<LoadWrapperType, LoadWrapperModelType> : LoadableShape
 76        where LoadWrapperType: LoadWrapper, new()
 77        where LoadWrapperModelType: LoadableShape.Model, new()
 78    {
 79        private bool failed = false;
 80        private event Action<BaseDisposable> OnFinishCallbacks;
 81        public System.Action<IDCLEntity> OnEntityShapeUpdated;
 82
 83        new public LoadWrapperModelType model
 84        {
 85            get
 86            {
 49687                if (base.model == null)
 088                    base.model = new LoadWrapperModelType();
 89
 49690                return base.model as LoadWrapperModelType;
 91            }
 92
 93            set
 94            {
 995                base.model = value;
 996            }
 97        }
 98
 99        new protected LoadWrapperModelType previousModel
 100        {
 101            get
 102            {
 386103                if (base.previousModel == null)
 0104                    base.previousModel = new LoadWrapperModelType();
 105
 386106                return base.previousModel as LoadWrapperModelType;
 107            }
 108
 109            set
 110            {
 79111                base.previousModel = value;
 79112            }
 113        }
 114
 67115        public LoadableShape()
 116        {
 67117            OnDetach += DetachShape;
 67118            OnAttach += AttachShape;
 67119        }
 120
 121        public override IEnumerator ApplyChanges(BaseModel newModel)
 122        {
 79123            LoadWrapperModelType model = (LoadWrapperModelType)newModel;
 124
 79125            bool updateVisibility = true;
 79126            bool updateCollisions = true;
 79127            bool triggerAttachment = true;
 128
 79129            if (previousModel != null)
 130            {
 70131                updateVisibility = previousModel.visible != model.visible;
 70132                updateCollisions = previousModel.withCollisions != model.withCollisions || previousModel.isPointerBlocke
 133
 70134                triggerAttachment = (!string.IsNullOrEmpty(model.src) && previousModel.src != model.src) ||
 135                                    (!string.IsNullOrEmpty(model.assetId) && previousModel.assetId != model.assetId);
 136            }
 137
 178138            foreach (var entity in attachedEntities)
 139            {
 10140                if (triggerAttachment)
 2141                    AttachShape(entity);
 142
 10143                if (updateVisibility)
 7144                    ConfigureVisibility(entity);
 145
 10146                if (updateCollisions)
 0147                    ConfigureColliders(entity);
 148
 10149                RaiseOnShapeUpdated(entity);
 150            }
 151
 79152            previousModel = model;
 79153            return null;
 154        }
 155
 156        protected virtual void AttachShape(IDCLEntity entity)
 157        {
 60158            ContentProvider provider = null;
 159
 60160            if (!string.IsNullOrEmpty(model.assetId))
 161            {
 1162                provider = AssetCatalogBridge.i.GetContentProviderForAssetIdInSceneObjectCatalog(model.assetId);
 163
 1164                if (string.IsNullOrEmpty(model.src))
 165                {
 0166                    SceneObject sceneObject = AssetCatalogBridge.i.GetSceneObjectById(model.assetId);
 167
 0168                    if (sceneObject == null)
 169                    {
 170#if UNITY_EDITOR
 0171                        Debug.LogWarning($"LoadableShape '{model.assetId}' not found in catalog, probably asset pack del
 172#endif
 0173                        failed = true;
 0174                        OnLoadFailed(null, new Exception($"LoadableShape '{model.assetId}' not found in catalog, probabl
 0175                        return;
 176                    }
 177
 0178                    model.src = sceneObject.model;
 179                }
 180            }
 181
 60182            if (provider == null)
 59183                provider = scene.contentProvider;
 184
 60185            if (provider.HasContentsUrl(model.src))
 186            {
 60187                isLoaded = false;
 60188                entity.EnsureMeshGameObject(componentName + " mesh");
 189
 60190                LoadWrapperType loadableShape =
 191                    Environment.i.world.state.GetOrAddLoaderForEntity<LoadWrapperType>(entity);
 192
 60193                if (loadableShape is LoadWrapper_GLTF gltfLoadWrapper)
 59194                    gltfLoadWrapper.customContentProvider = provider;
 195
 60196                entity.meshesInfo.currentShape = this;
 197
 60198                loadableShape.entity = entity;
 199
 60200                bool initialVisibility = model.visible;
 201
 60202                if (!DataStore.i.debugConfig.isDebugMode.Get())
 53203                    initialVisibility &= entity.isInsideSceneBoundaries;
 204
 60205                loadableShape.initialVisibility = initialVisibility;
 206
 60207                loadableShape.Load(model.src, OnLoadCompleted, OnLoadFailed);
 208            }
 209            else
 210            {
 0211                var message = $"LoadableShape '{model.src}' not found";
 212
 0213                if (DataStore.i.debugConfig.isDebugMode.Get())
 214                {
 0215                    Debug.LogError(message);
 216                }
 217                else
 218                {
 219#if UNITY_EDITOR
 0220                    Debug.LogWarning(message);
 221#endif
 222                }
 223
 0224                failed = true;
 225            }
 0226        }
 227
 228        void ConfigureVisibility(IDCLEntity entity)
 229        {
 72230            var loadable = Environment.i.world.state.GetLoaderForEntity(entity);
 231
 72232            bool initialVisibility = model.visible;
 233
 72234            if (!DataStore.i.debugConfig.isDebugMode.Get())
 62235                initialVisibility &= entity.isInsideSceneBoundaries;
 236
 72237            if (loadable != null)
 72238                loadable.initialVisibility = initialVisibility;
 239
 72240            ConfigureVisibility(entity.meshRootGameObject, initialVisibility, entity.meshesInfo.renderers);
 241
 72242            UpdateAnimationStatus(entity, initialVisibility);
 72243        }
 244
 245        private void UpdateAnimationStatus(IDCLEntity entity, bool enabled)
 246        {
 99247            if (!scene.componentsManagerLegacy.HasComponent(entity, CLASS_ID_COMPONENT.ANIMATOR) &&
 248                entity.meshesInfo.animation != null)
 8249                entity.meshesInfo.animation.enabled = enabled;
 99250        }
 251
 252        protected virtual void ConfigureColliders(IDCLEntity entity)
 253        {
 58254            CollidersManager.i.ConfigureColliders(entity.meshRootGameObject, model.withCollisions && entity.isInsideScen
 58255        }
 256
 257        protected void OnLoadFailed(LoadWrapper loadWrapper, Exception exception)
 258        {
 0259            if (loadWrapper != null)
 0260                CleanFailedWrapper(loadWrapper);
 261
 0262            failed = true;
 0263            OnFinishCallbacks?.Invoke(this);
 0264            OnFinishCallbacks = null;
 0265        }
 266
 267        private void CleanFailedWrapper(LoadWrapper loadWrapper)
 268        {
 0269            if (loadWrapper == null)
 0270                return;
 271
 0272            if (loadWrapper.entity == null)
 0273                return;
 274
 0275            if (loadWrapper.entity.gameObject == null)
 0276                return;
 277
 0278            GameObject go = loadWrapper.entity.gameObject;
 279
 0280            go.name += " - Failed loading";
 0281        }
 282
 283        protected void OnLoadCompleted(LoadWrapper loadWrapper)
 284        {
 65285            IDCLEntity entity = loadWrapper.entity;
 286
 65287            if (entity.meshesInfo.currentShape == null)
 288            {
 0289                OnLoadFailed(loadWrapper, new Exception($"Entity {entity.entityId} current shape of mesh information is 
 0290                return;
 291            }
 292
 65293            isLoaded = true;
 65294            OnLoaded?.Invoke(this);
 295
 65296            entity.meshesInfo.meshRootGameObject = entity.meshRootGameObject;
 65297            entity.OnInsideBoundariesChanged += OnInsideBoundariesChanged;
 298
 65299            ConfigureVisibility(entity);
 65300            ConfigureColliders(entity);
 65301            RaiseOnShapeUpdated(entity);
 65302            RaiseOnShapeLoaded(entity);
 303
 65304            OnFinishCallbacks?.Invoke(this);
 65305            OnFinishCallbacks = null;
 65306        }
 307
 308        private void OnInsideBoundariesChanged(IDCLEntity entity, bool isInsideBoundaries)
 309        {
 27310            UpdateAnimationStatus(entity, isInsideBoundaries);
 27311        }
 312
 313        protected virtual void DetachShape(IDCLEntity entity)
 314        {
 49315            if (entity == null || entity.meshRootGameObject == null)
 0316                return;
 317
 49318            LoadWrapper loadWrapper = Environment.i.world.state.GetLoaderForEntity(entity);
 319
 49320            if (loadWrapper != null)
 321            {
 49322                entity.OnInsideBoundariesChanged -= OnInsideBoundariesChanged;
 49323                loadWrapper.Unload();
 324            }
 325
 49326            Environment.i.world.state.RemoveLoaderForEntity(entity);
 49327            entity.meshesInfo.CleanReferences();
 49328        }
 329
 330        public override void CallWhenReady(Action<ISharedComponent> callback)
 331        {
 4332            if (attachedEntities.Count == 0 || isLoaded || failed) { callback.Invoke(this); }
 2333            else { OnFinishCallbacks += callback; }
 2334        }
 335
 336        private void RaiseOnShapeUpdated(IDCLEntity entity)
 337        {
 75338            if (!isLoaded)
 4339                return;
 340
 71341            entity.OnShapeUpdated?.Invoke(entity);
 71342        }
 343
 344        private void RaiseOnShapeLoaded(IDCLEntity entity)
 345        {
 65346            if (!isLoaded)
 0347                return;
 348
 65349            entity.OnShapeLoaded?.Invoke(entity);
 5350        }
 351    }
 352}