< 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:17
Uncovered lines:4
Coverable lines:21
Total lines:303
Line coverage:80.9% (17 of 21)
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
 6420            public override BaseModel GetDataFromJSON(string json) { return Utils.SafeFromJson<Model>(json); }
 21        }
 22
 8423        protected Model previousModel = new Model();
 24
 125        protected static Dictionary<GameObject, LoadWrapper> attachedLoaders = new Dictionary<GameObject, LoadWrapper>()
 26
 27        public static LoadWrapper GetLoaderForEntity(IDCLEntity entity)
 28        {
 22929            if (entity.meshRootGameObject == null)
 30            {
 031                Debug.LogWarning("NULL meshRootGameObject at GetLoaderForEntity()");
 032                return null;
 33            }
 34
 22935            attachedLoaders.TryGetValue(entity.meshRootGameObject, out LoadWrapper result);
 22936            return result;
 37        }
 38
 39        public static T GetOrAddLoaderForEntity<T>(IDCLEntity entity)
 40            where T : LoadWrapper, new()
 41        {
 9342            if (!attachedLoaders.TryGetValue(entity.meshRootGameObject, out LoadWrapper result))
 43            {
 8544                result = new T();
 8545                attachedLoaders.Add(entity.meshRootGameObject, result);
 46            }
 47
 9348            return result as T;
 49        }
 50
 25251        public LoadableShape() { model = new Model(); }
 52
 053        public override int GetClassId() { return -1; }
 54
 055        public override IEnumerator ApplyChanges(BaseModel newModel) { return null; }
 56
 57        public override bool IsVisible()
 58        {
 3559            Model model = (Model) this.model;
 3560            return model.visible;
 61        }
 62
 63        public override bool HasCollisions()
 64        {
 1865            Model model = (Model) this.model;
 1866            return model.withCollisions;
 67        }
 68
 69        public string GetAssetId()
 70        {
 4671            Model model = (Model) this.model;
 4672            return model.assetId;
 73        }
 74    }
 75
 76    public class LoadableShape<LoadWrapperType, LoadWrapperModelType> : LoadableShape
 77        where LoadWrapperType : LoadWrapper, new()
 78        where LoadWrapperModelType : LoadableShape.Model, new()
 79    {
 80        private bool isLoaded = false;
 81        private bool failed = false;
 82        private event Action<BaseDisposable> OnFinishCallbacks;
 83        public System.Action<IDCLEntity> OnEntityShapeUpdated;
 84
 85        new public LoadWrapperModelType model
 86        {
 87            get
 88            {
 89                if (base.model == null)
 90                    base.model = new LoadWrapperModelType();
 91
 92                return base.model as LoadWrapperModelType;
 93            }
 94            set { base.model = value; }
 95        }
 96
 97        new protected LoadWrapperModelType previousModel
 98        {
 99            get
 100            {
 101                if (base.previousModel == null)
 102                    base.previousModel = new LoadWrapperModelType();
 103
 104                return base.previousModel as LoadWrapperModelType;
 105            }
 106            set { base.previousModel = value; }
 107        }
 108
 109        public LoadableShape()
 110        {
 111            OnDetach += DetachShape;
 112            OnAttach += AttachShape;
 113        }
 114
 115        public override IEnumerator ApplyChanges(BaseModel newModel)
 116        {
 117            LoadWrapperModelType model = (LoadWrapperModelType) newModel;
 118
 119            bool updateVisibility = true;
 120            bool updateCollisions = true;
 121            bool triggerAttachment = true;
 122
 123            if (previousModel != null)
 124            {
 125                updateVisibility = previousModel.visible != model.visible;
 126                updateCollisions = previousModel.withCollisions != model.withCollisions || previousModel.isPointerBlocke
 127                triggerAttachment = (!string.IsNullOrEmpty(model.src) && previousModel.src != model.src) ||
 128                                    (!string.IsNullOrEmpty(model.assetId) && previousModel.assetId != model.assetId);
 129            }
 130
 131            foreach (var entity in attachedEntities)
 132            {
 133                if (triggerAttachment)
 134                    AttachShape(entity);
 135
 136                if (updateVisibility)
 137                    ConfigureVisibility(entity);
 138
 139                if (updateCollisions)
 140                    ConfigureColliders(entity);
 141
 142                RaiseOnShapeUpdated(entity);
 143            }
 144
 145            previousModel = model;
 146            return null;
 147        }
 148
 149        protected virtual void AttachShape(IDCLEntity entity)
 150        {
 151            ContentProvider provider = null;
 152
 153            if (!string.IsNullOrEmpty(model.assetId))
 154            {
 155                provider = AssetCatalogBridge.i.GetContentProviderForAssetIdInSceneObjectCatalog(model.assetId);
 156                if (string.IsNullOrEmpty(model.src))
 157                {
 158                    SceneObject sceneObject = AssetCatalogBridge.i.GetSceneObjectById(model.assetId);
 159                    if (sceneObject == null)
 160                    {
 161#if UNITY_EDITOR
 162                        Debug.LogWarning($"LoadableShape '{model.assetId}' not found in catalog, probably asset pack del
 163#endif
 164                        failed = true;
 165                        OnLoadFailed(null);
 166                        return;
 167                    }
 168                    model.src = sceneObject.model;
 169                }
 170            }
 171
 172            if (provider == null)
 173                provider = scene.contentProvider;
 174
 175            if (provider.HasContentsUrl(model.src))
 176            {
 177                isLoaded = false;
 178                entity.EnsureMeshGameObject(componentName + " mesh");
 179
 180                LoadWrapperType loadableShape = GetOrAddLoaderForEntity<LoadWrapperType>(entity);
 181
 182                if (loadableShape is LoadWrapper_GLTF gltfLoadWrapper)
 183                    gltfLoadWrapper.customContentProvider = provider;
 184
 185                entity.meshesInfo.currentShape = this;
 186
 187                loadableShape.entity = entity;
 188                loadableShape.useVisualFeedback = Configuration.ParcelSettings.VISUAL_LOADING_ENABLED;
 189                loadableShape.initialVisibility = model.visible;
 190                loadableShape.Load(model.src, OnLoadCompleted, OnLoadFailed);
 191            }
 192            else
 193            {
 194#if UNITY_EDITOR
 195                Debug.LogWarning($"LoadableShape '{model.src}' not found in scene '{scene.sceneData.id}' mappings");
 196#endif
 197                failed = true;
 198            }
 199        }
 200
 201        void ConfigureVisibility(IDCLEntity entity)
 202        {
 203            var loadable = GetLoaderForEntity(entity);
 204
 205            if (loadable != null)
 206                loadable.initialVisibility = model.visible;
 207
 208            ConfigureVisibility(entity.meshRootGameObject, model.visible, entity.meshesInfo.renderers);
 209        }
 210
 211        protected virtual void ConfigureColliders(IDCLEntity entity) { CollidersManager.i.ConfigureColliders(entity.mesh
 212
 213        protected void OnLoadFailed(LoadWrapper loadWrapper)
 214        {
 215            if (loadWrapper != null)
 216                CleanFailedWrapper(loadWrapper);
 217
 218            failed = true;
 219            OnFinishCallbacks?.Invoke(this);
 220            OnFinishCallbacks = null;
 221        }
 222
 223        void CleanFailedWrapper(LoadWrapper loadWrapper)
 224        {
 225            if (loadWrapper == null)
 226                return;
 227            if (loadWrapper.entity == null)
 228                return;
 229            if (loadWrapper.entity.gameObject == null)
 230                return;
 231
 232            GameObject go = loadWrapper.entity.gameObject;
 233
 234            go.name += " - Failed loading";
 235
 236            MaterialTransitionController[] transitionController =
 237                go.GetComponentsInChildren<MaterialTransitionController>(true);
 238
 239            for (int i = 0; i < transitionController.Length; i++)
 240            {
 241                MaterialTransitionController material = transitionController[i];
 242                Object.Destroy(material);
 243            }
 244        }
 245
 246        protected void OnLoadCompleted(LoadWrapper loadWrapper)
 247        {
 248            IDCLEntity entity = loadWrapper.entity;
 249
 250            if (entity.meshesInfo.currentShape == null)
 251            {
 252                OnLoadFailed(loadWrapper);
 253                return;
 254            }
 255
 256            isLoaded = true;
 257
 258            entity.meshesInfo.renderers = entity.meshRootGameObject.GetComponentsInChildren<Renderer>();
 259
 260            var model = (Model) (entity.meshesInfo.currentShape as LoadableShape).GetModel();
 261            ConfigureVisibility(entity.meshRootGameObject, model.visible, loadWrapper.entity.meshesInfo.renderers);
 262
 263            ConfigureColliders(entity);
 264
 265            RaiseOnShapeUpdated(entity);
 266
 267            OnFinishCallbacks?.Invoke(this);
 268            OnFinishCallbacks = null;
 269        }
 270
 271        protected virtual void DetachShape(IDCLEntity entity)
 272        {
 273            if (entity == null || entity.meshRootGameObject == null)
 274                return;
 275
 276            LoadWrapper loadWrapper = GetLoaderForEntity(entity);
 277
 278            loadWrapper?.Unload();
 279
 280            entity.meshesInfo.CleanReferences();
 281        }
 282
 283        public override void CallWhenReady(Action<ISharedComponent> callback)
 284        {
 285            if (attachedEntities.Count == 0 || isLoaded || failed)
 286            {
 287                callback.Invoke(this);
 288            }
 289            else
 290            {
 291                OnFinishCallbacks += callback;
 292            }
 293        }
 294
 295        private void RaiseOnShapeUpdated(IDCLEntity entity)
 296        {
 297            if (!isLoaded)
 298                return;
 299
 300            entity.OnShapeUpdated?.Invoke(entity);
 301        }
 302    }
 303}