< Summary

Class:DCL.Components.ParametrizedShape[T]
Assembly:DCL.Components.ParametrizedShape
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/ParametrizedShapes/ParametrizedShape.cs
Covered lines:108
Uncovered lines:7
Coverable lines:115
Total lines:248
Line coverage:93.9% (108 of 115)
Covered branches:0
Total branches:0
Covered methods:15
Total methods:17
Method coverage:88.2% (15 of 17)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
ParametrizedShape()0%110100%
GenerateGeometry()0%2100%
DestroyGeometry()0%2.032080%
UpdateFromModel(...)0%110100%
UpdateRenderer(...)0%990100%
OnShapeAttached(...)0%33094.74%
OnShapeFinishedLoading()0%550100%
OnShapeDetached(...)0%4.024090%
ApplyChanges(...)0%990100%
AttachTo(...)0%2.062075%
IsVisible()0%110100%
HasCollisions()0%110100%
ShouldGenerateNewMesh(...)0%2100%
RemoveRendereableFromDataStore(...)0%220100%
AddRendereableToDataStore(...)0%2.012088.89%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/ParametrizedShapes/ParametrizedShape.cs

#LineLine coverage
 1using DCL.Helpers;
 2using DCL.Models;
 3using System.Collections;
 4using System.Collections.Generic;
 5using Cysharp.Threading.Tasks;
 6using UnityEngine;
 7
 8namespace DCL.Components
 9{
 10    public abstract class ParametrizedShape<T> : BaseShape
 11        where T : BaseShape.Model, new()
 12    {
 13        private const string PARAMETRIZED_SHAPE_TAG = "FromParametrized";
 14
 17515        public Dictionary<IDCLEntity, Rendereable> attachedRendereables = new Dictionary<IDCLEntity, Rendereable>();
 16        bool visibilityDirty = false;
 17        bool collisionsDirty = false;
 18
 19        public virtual Mesh GenerateGeometry()
 20        {
 021            return null;
 22        }
 23
 24        protected virtual void DestroyGeometry()
 25        {
 4626            if (currentMesh == null)
 027                return;
 28
 4629            Object.Destroy(currentMesh);
 4630            currentMesh = null;
 4631        }
 32
 190233        public Mesh currentMesh { get; protected set; }
 34        private Model previousModel;
 35        private Model cachedModel;
 36
 17537        public ParametrizedShape()
 38        {
 17539            OnAttach += OnShapeAttached;
 17540            OnDetach += OnShapeDetached;
 17541        }
 42
 43        public override void UpdateFromModel(BaseModel newModel)
 44        {
 24645            cachedModel = (Model) newModel;
 24646            base.UpdateFromModel(newModel);
 24647        }
 48
 49        void UpdateRenderer(IDCLEntity entity, Model model = null)
 50        {
 26651            if (model == null)
 19052                model = (T) this.model;
 53
 26654            if (visibilityDirty)
 55            {
 22556                bool shouldBeVisible = model.visible;
 22557                if (!DataStore.i.debugConfig.isDebugMode.Get())
 21458                    shouldBeVisible &= entity.isInsideSceneBoundaries;
 59
 22560                ConfigureVisibility(entity.meshRootGameObject, shouldBeVisible, entity.meshesInfo.renderers);
 22561                visibilityDirty = false;
 62            }
 63
 26664            if (collisionsDirty)
 65            {
 21366                CollidersManager.i.ConfigureColliders(entity.meshRootGameObject, model.withCollisions && entity.isInside
 21367                collisionsDirty = false;
 68            }
 69
 26670            if (entity.meshesInfo.meshFilters.Length > 0 && entity.meshesInfo.meshFilters[0].sharedMesh != currentMesh)
 71            {
 372                entity.meshesInfo.UpdateExistingMeshAtIndex(currentMesh, 0);
 73            }
 74
 26675            Environment.i.world.sceneBoundsChecker?.AddEntityToBeChecked(entity);
 26676        }
 77
 78        void OnShapeAttached(IDCLEntity entity)
 79        {
 19080            if (entity == null)
 081                return;
 82
 83            // First we remove the old rendereable, then we compute and add the new one.
 19084            RemoveRendereableFromDataStore(entity);
 85
 19086            entity.EnsureMeshGameObject(componentName + " mesh");
 87
 19088            if (currentMesh == null)
 89            {
 16590                currentMesh = GenerateGeometry();
 91            }
 92
 19093            MeshFilter meshFilter = entity.meshRootGameObject.AddComponent<MeshFilter>();
 19094            MeshRenderer meshRenderer = entity.meshRootGameObject.AddComponent<MeshRenderer>();
 95
 19096            entity.meshesInfo.OverrideRenderers( new Renderer[] { meshRenderer });
 19097            entity.meshesInfo.currentShape = this;
 98
 19099            meshFilter.sharedMesh = currentMesh;
 190100            meshFilter.gameObject.tag = PARAMETRIZED_SHAPE_TAG;
 101
 190102            meshRenderer.sharedMaterial = Utils.EnsureResourcesMaterial("Materials/Default");
 103
 190104            visibilityDirty = true;
 190105            collisionsDirty = true;
 190106            UpdateRenderer(entity);
 190107            OnShapeFinishedLoading(entity);
 190108            AddRendereableToDataStore(entity);
 190109        }
 110
 111
 112        async UniTaskVoid OnShapeFinishedLoading(IDCLEntity entity)
 113        {
 114            // We need to wait for a frame so that MaterialTransitionController has been destroyed.
 190115            await UniTask.Yield();
 116
 190117            entity.OnShapeUpdated?.Invoke(entity);
 190118            DCL.Environment.i.world.sceneBoundsChecker?.AddEntityToBeChecked(entity);
 190119        }
 120
 121        void OnShapeDetached(IDCLEntity entity)
 122        {
 146123            if (entity == null || entity.meshRootGameObject == null)
 0124                return;
 125
 146126            if (attachedEntities.Count == 0)
 127            {
 121128                DestroyGeometry();
 121129                Utils.CleanMaterials(entity.meshRootGameObject.GetComponent<Renderer>());
 121130                currentMesh = null;
 131            }
 132
 146133            Utils.SafeDestroy(entity.meshRootGameObject);
 146134            entity.meshesInfo.CleanReferences();
 135
 146136            RemoveRendereableFromDataStore(entity);
 146137        }
 138
 139        public override IEnumerator ApplyChanges(BaseModel newModelRaw)
 140        {
 246141            var newModel = (T) newModelRaw;
 142
 246143            if (previousModel != null)
 144            {
 71145                visibilityDirty = newModel.visible != previousModel.visible;
 71146                collisionsDirty = newModel.withCollisions != previousModel.withCollisions || newModel.isPointerBlocker !
 147            }
 148
 246149            bool shouldGenerateMesh = ShouldGenerateNewMesh(previousModel);
 150
 151            //NOTE(Brian): Only generate meshes here if they already are attached to something.
 152            //             Otherwise, the mesh will be created on the OnShapeAttached.
 246153            if (attachedEntities.Count > 0)
 154            {
 60155                using (var iterator = attachedEntities.GetEnumerator())
 156                {
 136157                    while (iterator.MoveNext())
 158                    {
 76159                        var entity = iterator.Current;
 76160                        RemoveRendereableFromDataStore(entity);
 161                    }
 60162                }
 163
 60164                if (shouldGenerateMesh)
 165                {
 6166                    DestroyGeometry();
 6167                    currentMesh = GenerateGeometry();
 168                }
 169
 60170                using (var iterator = attachedEntities.GetEnumerator())
 171                {
 60172                    bool cachedVisibilityDirty = visibilityDirty;
 60173                    bool cachedCollisionDirty = collisionsDirty;
 136174                    while (iterator.MoveNext())
 175                    {
 176                        //NOTE(Alex): Since UpdateRenderer updates the dirty flags as well we have to make sure every en
 177                        //            gets updated accordingly to the original flags.
 76178                        visibilityDirty = cachedVisibilityDirty;
 76179                        collisionsDirty = cachedCollisionDirty;
 180
 76181                        var entity = iterator.Current;
 76182                        UpdateRenderer(entity, newModel);
 183
 76184                        entity.OnShapeUpdated?.Invoke(entity);
 185                    }
 60186                }
 187
 60188                using (var iterator = attachedEntities.GetEnumerator())
 189                {
 136190                    while (iterator.MoveNext())
 191                    {
 76192                        var entity = iterator.Current;
 76193                        AddRendereableToDataStore(entity);
 194                    }
 60195                }
 196            }
 197
 246198            previousModel = newModel;
 246199            return null;
 200        }
 201
 202        public override void AttachTo(IDCLEntity entity, System.Type overridenAttachedType = null)
 203        {
 190204            if (attachedEntities.Contains(entity))
 0205                return;
 206
 190207            base.AttachTo(entity);
 190208        }
 209
 132210        public override bool IsVisible() { return cachedModel.visible; }
 211
 170212        public override bool HasCollisions() { return cachedModel.withCollisions; }
 213
 0214        protected virtual bool ShouldGenerateNewMesh(BaseShape.Model newModel) { return true; }
 215
 216        private void RemoveRendereableFromDataStore(IDCLEntity entity)
 217        {
 412218            if (!attachedRendereables.ContainsKey(entity))
 190219                return;
 220
 222221            DataStore.i.sceneWorldObjects.RemoveRendereable(entity.scene.sceneData.sceneNumber, attachedRendereables[ent
 222222            attachedRendereables.Remove(entity);
 222223        }
 224
 225        private void AddRendereableToDataStore(IDCLEntity entity)
 226        {
 266227            if (attachedRendereables.ContainsKey(entity))
 0228                return;
 229
 266230            int triangleCount = currentMesh.triangles.Length;
 231
 266232            var newRendereable =
 233                new Rendereable()
 234                {
 235                    container = entity.meshRootGameObject,
 236                    totalTriangleCount = triangleCount,
 237                    meshes = new HashSet<Mesh>() { currentMesh },
 238                    meshToTriangleCount = new Dictionary<Mesh, int>() { { currentMesh, triangleCount } }
 239                };
 240
 266241            newRendereable.renderers = MeshesInfoUtils.ExtractUniqueRenderers(entity.meshRootGameObject);
 266242            newRendereable.ownerId = entity.entityId;
 243
 266244            attachedRendereables.Add(entity, newRendereable);
 266245            DataStore.i.sceneWorldObjects.AddRendereable(entity.scene.sceneData.sceneNumber, newRendereable);
 266246        }
 247    }
 248}