< 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:104
Uncovered lines:8
Coverable lines:112
Total lines:245
Line coverage:92.8% (104 of 112)
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%44094.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    {
 17413        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
 17435        public ParametrizedShape()
 36        {
 17437            OnAttach += OnShapeAttached;
 17438            OnDetach += OnShapeDetached;
 17439        }
 40
 41        public override void UpdateFromModel(BaseModel newModel)
 42        {
 24343            cachedModel = (Model) newModel;
 24344            base.UpdateFromModel(newModel);
 24345        }
 46
 47        void UpdateRenderer(IDCLEntity entity, Model model = null)
 48        {
 24749            if (model == null)
 18150                model = (T) this.model;
 51
 24752            if (visibilityDirty)
 53            {
 20654                ConfigureVisibility(entity.meshRootGameObject, model.visible && entity.isInsideSceneBoundaries, entity.e
 20655                visibilityDirty = false;
 56            }
 57
 24758            if (collisionsDirty)
 59            {
 20460                CollidersManager.i.ConfigureColliders(entity.meshRootGameObject, model.withCollisions && entity.isInside
 20461                collisionsDirty = false;
 62            }
 63
 24764            if (entity.meshesInfo.meshFilters.Length > 0 && entity.meshesInfo.meshFilters[0].sharedMesh != currentMesh)
 65            {
 366                entity.meshesInfo.UpdateExistingMeshAtIndex(currentMesh, 0);
 67            }
 68
 24769            DCL.Environment.i.world.sceneBoundsChecker?.AddEntityToBeChecked(entity);
 24770        }
 71
 72        void OnShapeAttached(IDCLEntity entity)
 73        {
 18174            if (entity == null)
 075                return;
 76
 77            // First we remove the old rendereable, then we compute and add the new one.
 18178            RemoveRendereableFromDataStore(entity);
 79
 18180            entity.EnsureMeshGameObject(componentName + " mesh");
 81
 18182            if (currentMesh == null)
 83            {
 16484                currentMesh = GenerateGeometry();
 85            }
 86
 18187            MeshFilter meshFilter = entity.meshRootGameObject.AddComponent<MeshFilter>();
 18188            MeshRenderer meshRenderer = entity.meshRootGameObject.AddComponent<MeshRenderer>();
 89
 18190            entity.meshesInfo.renderers = new Renderer[] { meshRenderer };
 18191            entity.meshesInfo.currentShape = this;
 92
 18193            meshFilter.sharedMesh = currentMesh;
 94
 18195            if (!Configuration.ParcelSettings.VISUAL_LOADING_ENABLED)
 96            {
 18097                meshRenderer.sharedMaterial = Utils.EnsureResourcesMaterial("Materials/Default");
 98
 99            }
 100
 181101            visibilityDirty = true;
 181102            collisionsDirty = true;
 181103            UpdateRenderer(entity);
 181104            OnShapeFinishedLoading(entity);
 181105            AddRendereableToDataStore(entity);
 181106        }
 107
 108
 109        async UniTaskVoid OnShapeFinishedLoading(IDCLEntity entity)
 110        {
 111            // We need to wait for a frame so that MaterialTransitionController has been destroyed.
 181112            await UniTask.Yield();
 113
 181114            entity.OnShapeUpdated?.Invoke(entity);
 181115            DCL.Environment.i.world.sceneBoundsChecker?.AddEntityToBeChecked(entity);
 181116        }
 117
 118        void OnShapeDetached(IDCLEntity entity)
 119        {
 137120            if (entity == null || entity.meshRootGameObject == null)
 0121                return;
 122
 137123            if (attachedEntities.Count == 0)
 124            {
 120125                DestroyGeometry();
 120126                Utils.CleanMaterials(entity.meshRootGameObject.GetComponent<Renderer>());
 120127                currentMesh = null;
 128            }
 129
 137130            Utils.SafeDestroy(entity.meshRootGameObject);
 137131            entity.meshesInfo.CleanReferences();
 132
 137133            RemoveRendereableFromDataStore(entity);
 137134        }
 135
 136        public override IEnumerator ApplyChanges(BaseModel newModelRaw)
 137        {
 243138            var newModel = (T) newModelRaw;
 139
 243140            if (previousModel != null)
 141            {
 69142                visibilityDirty = newModel.visible != previousModel.visible;
 69143                collisionsDirty = newModel.withCollisions != previousModel.withCollisions || newModel.isPointerBlocker !
 144            }
 145
 243146            bool shouldGenerateMesh = ShouldGenerateNewMesh(previousModel);
 147
 148            //NOTE(Brian): Only generate meshes here if they already are attached to something.
 149            //             Otherwise, the mesh will be created on the OnShapeAttached.
 243150            if (attachedEntities.Count > 0)
 151            {
 58152                using (var iterator = attachedEntities.GetEnumerator())
 153                {
 124154                    while (iterator.MoveNext())
 155                    {
 66156                        var entity = iterator.Current;
 66157                        RemoveRendereableFromDataStore(entity);
 158                    }
 58159                }
 160
 58161                if (shouldGenerateMesh)
 162                {
 6163                    DestroyGeometry();
 6164                    currentMesh = GenerateGeometry();
 165                }
 166
 58167                using (var iterator = attachedEntities.GetEnumerator())
 168                {
 58169                    bool cachedVisibilityDirty = visibilityDirty;
 58170                    bool cachedCollisionDirty = collisionsDirty;
 124171                    while (iterator.MoveNext())
 172                    {
 173                        //NOTE(Alex): Since UpdateRenderer updates the dirty flags as well we have to make sure every en
 174                        //            gets updated accordingly to the original flags.
 66175                        visibilityDirty = cachedVisibilityDirty;
 66176                        collisionsDirty = cachedCollisionDirty;
 177
 66178                        var entity = iterator.Current;
 66179                        UpdateRenderer(entity, newModel);
 180
 66181                        entity.OnShapeUpdated?.Invoke(entity);
 182                    }
 58183                }
 184
 58185                using (var iterator = attachedEntities.GetEnumerator())
 186                {
 124187                    while (iterator.MoveNext())
 188                    {
 66189                        var entity = iterator.Current;
 66190                        AddRendereableToDataStore(entity);
 191                    }
 58192                }
 193            }
 194
 243195            previousModel = newModel;
 243196            return null;
 197        }
 198
 199        public override void AttachTo(IDCLEntity entity, System.Type overridenAttachedType = null)
 200        {
 181201            if (attachedEntities.Contains(entity))
 0202                return;
 203
 181204            base.AttachTo(entity);
 181205        }
 206
 119207        public override bool IsVisible() { return cachedModel.visible; }
 208
 149209        public override bool HasCollisions() { return cachedModel.withCollisions; }
 210
 0211        protected virtual bool ShouldGenerateNewMesh(BaseShape.Model newModel) { return true; }
 212
 213        private void RemoveRendereableFromDataStore(IDCLEntity entity)
 214        {
 384215            if (!attachedRendereables.ContainsKey(entity))
 181216                return;
 217
 203218            DataStore.i.sceneWorldObjects.RemoveRendereable(entity.scene.sceneData.id, attachedRendereables[entity]);
 203219            attachedRendereables.Remove(entity);
 203220        }
 221
 222        private void AddRendereableToDataStore(IDCLEntity entity)
 223        {
 247224            if (attachedRendereables.ContainsKey(entity))
 0225                return;
 226
 247227            int triangleCount = currentMesh.triangles.Length;
 228
 247229            var newRendereable =
 230                new Rendereable()
 231                {
 232                    container = entity.meshRootGameObject,
 233                    totalTriangleCount = triangleCount,
 234                    meshes = new HashSet<Mesh>() { currentMesh },
 235                    meshToTriangleCount = new Dictionary<Mesh, int>() { { currentMesh, triangleCount } }
 236                };
 237
 247238            newRendereable.renderers = MeshesInfoUtils.ExtractUniqueRenderers(entity.meshRootGameObject);
 247239            newRendereable.ownerId = entity.entityId;
 240
 247241            attachedRendereables.Add(entity, newRendereable);
 247242            DataStore.i.sceneWorldObjects.AddRendereable(entity.scene.sceneData.id, newRendereable);
 247243        }
 244    }
 245}