< Summary

Class:DCL.Components.LoadableShape
Assembly:MainScripts
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/LoadableShapes/LoadableShape.cs
Covered lines:18
Uncovered lines:4
Coverable lines:22
Total lines:316
Line coverage:81.8% (18 of 22)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
GetDataFromJSON(...)0%110100%
LoadableShape()0%110100%
LoadableShape()0%110100%
GetLoaderForEntity(...)0%2.262060%
GetOrAddLoaderForEntity[T](...)0%220100%
GetClassId()0%2100%
ApplyChanges(...)0%2100%
IsVisible()0%110100%
HasCollisions()0%110100%
GetAssetId()0%110100%

File(s)

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

#LineLine coverage
 1using System;
 2using DCL.Controllers;
 3using DCL.Helpers;
 4using DCL.Models;
 5using System.Collections;
 6using UnityEngine;
 7using Object = UnityEngine.Object;
 8using System.Collections.Generic;
 9
 10namespace DCL.Components
 11{
 12    public class LoadableShape : BaseShape, IAssetCatalogReferenceHolder
 13    {
 14        [System.Serializable]
 15        public new class Model : BaseShape.Model
 16        {
 17            public string src;
 18            public string assetId;
 19
 6620            public override BaseModel GetDataFromJSON(string json) { return Utils.SafeFromJson<Model>(json); }
 21        }
 22
 923        public bool isLoaded { get; protected set; }
 24
 25        public Action<LoadableShape> OnLoaded;
 26
 8627        protected Model previousModel = new Model();
 28
 129        protected static Dictionary<GameObject, LoadWrapper> attachedLoaders = new Dictionary<GameObject, LoadWrapper>()
 30
 31        public static LoadWrapper GetLoaderForEntity(IDCLEntity entity)
 32        {
 22733            if (entity.meshRootGameObject == null)
 34            {
 035                Debug.LogWarning("NULL meshRootGameObject at GetLoaderForEntity()");
 036                return null;
 37            }
 38
 22739            attachedLoaders.TryGetValue(entity.meshRootGameObject, out LoadWrapper result);
 22740            return result;
 41        }
 42
 43        public static T GetOrAddLoaderForEntity<T>(IDCLEntity entity)
 44            where T : LoadWrapper, new()
 45        {
 8946            if (!attachedLoaders.TryGetValue(entity.meshRootGameObject, out LoadWrapper result))
 47            {
 8748                result = new T();
 8749                attachedLoaders.Add(entity.meshRootGameObject, result);
 50            }
 51
 8952            return result as T;
 53        }
 54
 25855        public LoadableShape() { model = new Model(); }
 56
 057        public override int GetClassId() { return -1; }
 58
 059        public override IEnumerator ApplyChanges(BaseModel newModel) { return null; }
 60
 61        public override bool IsVisible()
 62        {
 5563            Model model = (Model) this.model;
 5564            return model.visible;
 65        }
 66
 67        public override bool HasCollisions()
 68        {
 1969            Model model = (Model) this.model;
 1970            return model.withCollisions;
 71        }
 72
 73        public string GetAssetId()
 74        {
 5175            Model model = (Model) this.model;
 5176            return model.assetId;
 77        }
 78    }
 79
 80    public class LoadableShape<LoadWrapperType, LoadWrapperModelType> : LoadableShape
 81        where LoadWrapperType : LoadWrapper, new()
 82        where LoadWrapperModelType : LoadableShape.Model, new()
 83    {
 84        private bool failed = false;
 85        private event Action<BaseDisposable> OnFinishCallbacks;
 86        public System.Action<IDCLEntity> OnEntityShapeUpdated;
 87
 88        new public LoadWrapperModelType model
 89        {
 90            get
 91            {
 92                if (base.model == null)
 93                    base.model = new LoadWrapperModelType();
 94
 95                return base.model as LoadWrapperModelType;
 96            }
 97            set { base.model = value; }
 98        }
 99
 100        new protected LoadWrapperModelType previousModel
 101        {
 102            get
 103            {
 104                if (base.previousModel == null)
 105                    base.previousModel = new LoadWrapperModelType();
 106
 107                return base.previousModel as LoadWrapperModelType;
 108            }
 109            set { base.previousModel = value; }
 110        }
 111
 112        public LoadableShape()
 113        {
 114            OnDetach += DetachShape;
 115            OnAttach += AttachShape;
 116        }
 117
 118        public override IEnumerator ApplyChanges(BaseModel newModel)
 119        {
 120            LoadWrapperModelType model = (LoadWrapperModelType) newModel;
 121
 122            bool updateVisibility = true;
 123            bool updateCollisions = true;
 124            bool triggerAttachment = true;
 125
 126            if (previousModel != null)
 127            {
 128                updateVisibility = previousModel.visible != model.visible;
 129                updateCollisions = previousModel.withCollisions != model.withCollisions || previousModel.isPointerBlocke
 130                triggerAttachment = (!string.IsNullOrEmpty(model.src) && previousModel.src != model.src) ||
 131                                    (!string.IsNullOrEmpty(model.assetId) && previousModel.assetId != model.assetId);
 132            }
 133
 134            foreach (var entity in attachedEntities)
 135            {
 136                if (triggerAttachment)
 137                    AttachShape(entity);
 138
 139                if (updateVisibility)
 140                    ConfigureVisibility(entity);
 141
 142                if (updateCollisions)
 143                    ConfigureColliders(entity);
 144
 145                RaiseOnShapeUpdated(entity);
 146            }
 147
 148            previousModel = model;
 149            return null;
 150        }
 151
 152        protected virtual void AttachShape(IDCLEntity entity)
 153        {
 154            ContentProvider provider = null;
 155
 156            if (!string.IsNullOrEmpty(model.assetId))
 157            {
 158                provider = AssetCatalogBridge.i.GetContentProviderForAssetIdInSceneObjectCatalog(model.assetId);
 159                if (string.IsNullOrEmpty(model.src))
 160                {
 161                    SceneObject sceneObject = AssetCatalogBridge.i.GetSceneObjectById(model.assetId);
 162                    if (sceneObject == null)
 163                    {
 164#if UNITY_EDITOR
 165                        Debug.LogWarning($"LoadableShape '{model.assetId}' not found in catalog, probably asset pack del
 166#endif
 167                        failed = true;
 168                        OnLoadFailed(null);
 169                        return;
 170                    }
 171
 172                    model.src = sceneObject.model;
 173                }
 174            }
 175
 176            if (provider == null)
 177                provider = scene.contentProvider;
 178
 179            if (provider.HasContentsUrl(model.src))
 180            {
 181                isLoaded = false;
 182                entity.EnsureMeshGameObject(componentName + " mesh");
 183
 184                LoadWrapperType loadableShape = GetOrAddLoaderForEntity<LoadWrapperType>(entity);
 185
 186                if (loadableShape is LoadWrapper_GLTF gltfLoadWrapper)
 187                    gltfLoadWrapper.customContentProvider = provider;
 188
 189                entity.meshesInfo.currentShape = this;
 190
 191                loadableShape.entity = entity;
 192                loadableShape.useVisualFeedback = Configuration.ParcelSettings.VISUAL_LOADING_ENABLED;
 193                loadableShape.initialVisibility = model.visible;
 194                loadableShape.Load(model.src, OnLoadCompleted, OnLoadFailed);
 195            }
 196            else
 197            {
 198#if UNITY_EDITOR
 199                Debug.LogWarning($"LoadableShape '{model.src}' not found in scene '{scene.sceneData.id}' mappings");
 200#endif
 201                failed = true;
 202            }
 203        }
 204
 205        void ConfigureVisibility(IDCLEntity entity)
 206        {
 207            var loadable = GetLoaderForEntity(entity);
 208
 209            if (loadable != null)
 210                loadable.initialVisibility = model.visible;
 211
 212            ConfigureVisibility(entity.meshRootGameObject, model.visible, entity.meshesInfo.renderers);
 213        }
 214
 215        protected virtual void ConfigureColliders(IDCLEntity entity) { CollidersManager.i.ConfigureColliders(entity.mesh
 216
 217        protected void OnLoadFailed(LoadWrapper loadWrapper)
 218        {
 219            if (loadWrapper != null)
 220                CleanFailedWrapper(loadWrapper);
 221
 222            failed = true;
 223            OnFinishCallbacks?.Invoke(this);
 224            OnFinishCallbacks = null;
 225        }
 226
 227        void CleanFailedWrapper(LoadWrapper loadWrapper)
 228        {
 229            if (loadWrapper == null)
 230                return;
 231            if (loadWrapper.entity == null)
 232                return;
 233            if (loadWrapper.entity.gameObject == null)
 234                return;
 235
 236            GameObject go = loadWrapper.entity.gameObject;
 237
 238            go.name += " - Failed loading";
 239
 240            MaterialTransitionController[] transitionController =
 241                go.GetComponentsInChildren<MaterialTransitionController>(true);
 242
 243            for (int i = 0; i < transitionController.Length; i++)
 244            {
 245                MaterialTransitionController material = transitionController[i];
 246                Object.Destroy(material);
 247            }
 248        }
 249
 250        protected void OnLoadCompleted(LoadWrapper loadWrapper)
 251        {
 252            IDCLEntity entity = loadWrapper.entity;
 253
 254            if (entity.meshesInfo.currentShape == null)
 255            {
 256                OnLoadFailed(loadWrapper);
 257                return;
 258            }
 259
 260            isLoaded = true;
 261            OnLoaded?.Invoke(this);
 262
 263            entity.meshesInfo.renderers = entity.meshRootGameObject.GetComponentsInChildren<Renderer>();
 264
 265            var model = (Model) (entity.meshesInfo.currentShape as LoadableShape).GetModel();
 266
 267            ConfigureVisibility(entity.meshRootGameObject, model.visible, loadWrapper.entity.meshesInfo.renderers);
 268            ConfigureColliders(entity);
 269            RaiseOnShapeUpdated(entity);
 270            RaiseOnShapeLoaded(entity);
 271
 272            OnFinishCallbacks?.Invoke(this);
 273            OnFinishCallbacks = null;
 274        }
 275
 276        protected virtual void DetachShape(IDCLEntity entity)
 277        {
 278            if (entity == null || entity.meshRootGameObject == null)
 279                return;
 280
 281            LoadWrapper loadWrapper = GetLoaderForEntity(entity);
 282
 283            loadWrapper?.Unload();
 284
 285            entity.meshesInfo.CleanReferences();
 286        }
 287
 288        public override void CallWhenReady(Action<ISharedComponent> callback)
 289        {
 290            if (attachedEntities.Count == 0 || isLoaded || failed)
 291            {
 292                callback.Invoke(this);
 293            }
 294            else
 295            {
 296                OnFinishCallbacks += callback;
 297            }
 298        }
 299
 300        private void RaiseOnShapeUpdated(IDCLEntity entity)
 301        {
 302            if (!isLoaded)
 303                return;
 304
 305            entity.OnShapeUpdated?.Invoke(entity);
 306        }
 307
 308        private void RaiseOnShapeLoaded(IDCLEntity entity)
 309        {
 310            if (!isLoaded)
 311                return;
 312
 313            entity.OnShapeLoaded?.Invoke(entity);
 314        }
 315    }
 316}