< 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:115
Uncovered lines:8
Coverable lines:123
Total lines:259
Line coverage:93.4% (115 of 123)
Covered branches:0
Total branches:0

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%44096.3%
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    {
 17713        public Dictionary<IDCLEntity, Rendereable> attachedRendereables = new Dictionary<IDCLEntity, Rendereable>();
 14        bool visibilityDirty = false;
 15        bool collisionsDirty = false;
 16
 17        public virtual Mesh GenerateGeometry()
 18        {
 019            return null;
 20        }
 21
 22        protected virtual void DestroyGeometry()
 23        {
 4724            if (currentMesh == null)
 025                return;
 26
 4727            Object.Destroy(currentMesh);
 4728            currentMesh = null;
 4729        }
 30
 031        public Mesh currentMesh { get; protected set; }
 32        private Model previousModel;
 33        private Model cachedModel;
 34
 17735        public ParametrizedShape()
 36        {
 17737            OnAttach += OnShapeAttached;
 17738            OnDetach += OnShapeDetached;
 17739        }
 40
 41        public override void UpdateFromModel(BaseModel newModel)
 42        {
 24843            cachedModel = (Model) newModel;
 24844            base.UpdateFromModel(newModel);
 24845        }
 46
 47        void UpdateRenderer(IDCLEntity entity, Model model = null)
 48        {
 26849            if (model == null)
 19250                model = (T) this.model;
 51
 26852            if (visibilityDirty)
 53            {
 22754                bool shouldBeVisible = model.visible;
 22755                if (!DataStore.i.debugConfig.isDebugMode.Get())
 21656                    shouldBeVisible &= entity.isInsideSceneBoundaries;
 57
 22758                ConfigureVisibility(entity.meshRootGameObject, shouldBeVisible, entity.meshesInfo.renderers);
 22759                visibilityDirty = false;
 60            }
 61
 26862            if (collisionsDirty)
 63            {
 21564                CollidersManager.i.ConfigureColliders(entity.meshRootGameObject, model.withCollisions && entity.isInside
 21565                collisionsDirty = false;
 66            }
 67
 26868            if (entity.meshesInfo.meshFilters.Length > 0 && entity.meshesInfo.meshFilters[0].sharedMesh != currentMesh)
 69            {
 370                entity.meshesInfo.UpdateExistingMeshAtIndex(currentMesh, 0);
 71            }
 72
 26873            DCL.Environment.i.world.sceneBoundsChecker?.AddEntityToBeChecked(entity);
 26874        }
 75
 76        void OnShapeAttached(IDCLEntity entity)
 77        {
 19278            if (entity == null)
 079                return;
 80
 81            // First we remove the old rendereable, then we compute and add the new one.
 19282            RemoveRendereableFromDataStore(entity);
 83
 19284            entity.EnsureMeshGameObject(componentName + " mesh");
 85
 19286            if (currentMesh == null)
 87            {
 16788                currentMesh = GenerateGeometry();
 89            }
 90
 19291            MeshFilter meshFilter = entity.meshRootGameObject.AddComponent<MeshFilter>();
 19292            MeshRenderer meshRenderer = entity.meshRootGameObject.AddComponent<MeshRenderer>();
 93
 19294            entity.meshesInfo.renderers = new Renderer[] { meshRenderer };
 19295            entity.meshesInfo.currentShape = this;
 96
 19297            meshFilter.sharedMesh = currentMesh;
 98
 19299            if (Configuration.ParcelSettings.VISUAL_LOADING_ENABLED)
 100            {
 1101                MaterialTransitionController transition = entity.meshRootGameObject.AddComponent<MaterialTransitionContr
 1102                Material finalMaterial = Utils.EnsureResourcesMaterial("Materials/Default");
 1103                transition.delay = 0;
 1104                transition.useHologram = false;
 1105                transition.fadeThickness = 20;
 1106                transition.OnDidFinishLoading(finalMaterial);
 107
 3108                transition.onFinishedLoading += () => { OnShapeFinishedLoading(entity); };
 1109            }
 110            else
 111            {
 191112                meshRenderer.sharedMaterial = Utils.EnsureResourcesMaterial("Materials/Default");
 113            }
 114
 192115            visibilityDirty = true;
 192116            collisionsDirty = true;
 192117            UpdateRenderer(entity);
 192118            OnShapeFinishedLoading(entity);
 192119            AddRendereableToDataStore(entity);
 192120        }
 121
 122
 123        async UniTaskVoid OnShapeFinishedLoading(IDCLEntity entity)
 124        {
 125            // We need to wait for a frame so that MaterialTransitionController has been destroyed.
 193126            await UniTask.Yield();
 127
 193128            entity.OnShapeUpdated?.Invoke(entity);
 193129            DCL.Environment.i.world.sceneBoundsChecker?.AddEntityToBeChecked(entity);
 193130        }
 131
 132        void OnShapeDetached(IDCLEntity entity)
 133        {
 148134            if (entity == null || entity.meshRootGameObject == null)
 0135                return;
 136
 148137            if (attachedEntities.Count == 0)
 138            {
 123139                DestroyGeometry();
 123140                Utils.CleanMaterials(entity.meshRootGameObject.GetComponent<Renderer>());
 123141                currentMesh = null;
 142            }
 143
 148144            Utils.SafeDestroy(entity.meshRootGameObject);
 148145            entity.meshesInfo.CleanReferences();
 146
 148147            RemoveRendereableFromDataStore(entity);
 148148        }
 149
 150        public override IEnumerator ApplyChanges(BaseModel newModelRaw)
 151        {
 248152            var newModel = (T) newModelRaw;
 153
 248154            if (previousModel != null)
 155            {
 71156                visibilityDirty = newModel.visible != previousModel.visible;
 71157                collisionsDirty = newModel.withCollisions != previousModel.withCollisions || newModel.isPointerBlocker !
 158            }
 159
 248160            bool shouldGenerateMesh = ShouldGenerateNewMesh(previousModel);
 161
 162            //NOTE(Brian): Only generate meshes here if they already are attached to something.
 163            //             Otherwise, the mesh will be created on the OnShapeAttached.
 248164            if (attachedEntities.Count > 0)
 165            {
 60166                using (var iterator = attachedEntities.GetEnumerator())
 167                {
 136168                    while (iterator.MoveNext())
 169                    {
 76170                        var entity = iterator.Current;
 76171                        RemoveRendereableFromDataStore(entity);
 172                    }
 60173                }
 174
 60175                if (shouldGenerateMesh)
 176                {
 6177                    DestroyGeometry();
 6178                    currentMesh = GenerateGeometry();
 179                }
 180
 60181                using (var iterator = attachedEntities.GetEnumerator())
 182                {
 60183                    bool cachedVisibilityDirty = visibilityDirty;
 60184                    bool cachedCollisionDirty = collisionsDirty;
 136185                    while (iterator.MoveNext())
 186                    {
 187                        //NOTE(Alex): Since UpdateRenderer updates the dirty flags as well we have to make sure every en
 188                        //            gets updated accordingly to the original flags.
 76189                        visibilityDirty = cachedVisibilityDirty;
 76190                        collisionsDirty = cachedCollisionDirty;
 191
 76192                        var entity = iterator.Current;
 76193                        UpdateRenderer(entity, newModel);
 194
 76195                        entity.OnShapeUpdated?.Invoke(entity);
 196                    }
 60197                }
 198
 60199                using (var iterator = attachedEntities.GetEnumerator())
 200                {
 136201                    while (iterator.MoveNext())
 202                    {
 76203                        var entity = iterator.Current;
 76204                        AddRendereableToDataStore(entity);
 205                    }
 60206                }
 207            }
 208
 248209            previousModel = newModel;
 248210            return null;
 211        }
 212
 213        public override void AttachTo(IDCLEntity entity, System.Type overridenAttachedType = null)
 214        {
 192215            if (attachedEntities.Contains(entity))
 0216                return;
 217
 192218            base.AttachTo(entity);
 192219        }
 220
 119221        public override bool IsVisible() { return cachedModel.visible; }
 222
 154223        public override bool HasCollisions() { return cachedModel.withCollisions; }
 224
 0225        protected virtual bool ShouldGenerateNewMesh(BaseShape.Model newModel) { return true; }
 226
 227        private void RemoveRendereableFromDataStore(IDCLEntity entity)
 228        {
 416229            if (!attachedRendereables.ContainsKey(entity))
 192230                return;
 231
 224232            DataStore.i.sceneWorldObjects.RemoveRendereable(entity.scene.sceneData.id, attachedRendereables[entity]);
 224233            attachedRendereables.Remove(entity);
 224234        }
 235
 236        private void AddRendereableToDataStore(IDCLEntity entity)
 237        {
 268238            if (attachedRendereables.ContainsKey(entity))
 0239                return;
 240
 268241            int triangleCount = currentMesh.triangles.Length;
 242
 268243            var newRendereable =
 244                new Rendereable()
 245                {
 246                    container = entity.meshRootGameObject,
 247                    totalTriangleCount = triangleCount,
 248                    meshes = new HashSet<Mesh>() { currentMesh },
 249                    meshToTriangleCount = new Dictionary<Mesh, int>() { { currentMesh, triangleCount } }
 250                };
 251
 268252            newRendereable.renderers = MeshesInfoUtils.ExtractUniqueRenderers(entity.meshRootGameObject);
 268253            newRendereable.ownerId = entity.entityId;
 254
 268255            attachedRendereables.Add(entity, newRendereable);
 268256            DataStore.i.sceneWorldObjects.AddRendereable(entity.scene.sceneData.id, newRendereable);
 268257        }
 258    }
 259}