< 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:112
Uncovered lines:7
Coverable lines:119
Total lines:255
Line coverage:94.1% (112 of 119)
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.15%
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    {
 17313        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        {
 4524            if (currentMesh == null)
 025                return;
 26
 4527            Object.Destroy(currentMesh);
 4528            currentMesh = null;
 4529        }
 30
 188331        public Mesh currentMesh { get; protected set; }
 32        private Model previousModel;
 33        private Model cachedModel;
 34
 17335        public ParametrizedShape()
 36        {
 17337            OnAttach += OnShapeAttached;
 17338            OnDetach += OnShapeDetached;
 17339        }
 40
 41        public override void UpdateFromModel(BaseModel newModel)
 42        {
 24443            cachedModel = (Model) newModel;
 24444            base.UpdateFromModel(newModel);
 24445        }
 46
 47        void UpdateRenderer(IDCLEntity entity, Model model = null)
 48        {
 26449            if (model == null)
 18850                model = (T) this.model;
 51
 26452            if (visibilityDirty)
 53            {
 22354                ConfigureVisibility(entity.meshRootGameObject, model.visible && entity.isInsideSceneBoundaries, entity.m
 22355                visibilityDirty = false;
 56            }
 57
 26458            if (collisionsDirty)
 59            {
 21160                CollidersManager.i.ConfigureColliders(entity.meshRootGameObject, model.withCollisions && entity.isInside
 21161                collisionsDirty = false;
 62            }
 63
 26464            if (entity.meshesInfo.meshFilters.Length > 0 && entity.meshesInfo.meshFilters[0].sharedMesh != currentMesh)
 65            {
 366                entity.meshesInfo.UpdateExistingMeshAtIndex(currentMesh, 0);
 67            }
 68
 26469            DCL.Environment.i.world.sceneBoundsChecker?.AddEntityToBeChecked(entity);
 26470        }
 71
 72        void OnShapeAttached(IDCLEntity entity)
 73        {
 18874            if (entity == null)
 075                return;
 76
 77            // First we remove the old rendereable, then we compute and add the new one.
 18878            RemoveRendereableFromDataStore(entity);
 79
 18880            entity.EnsureMeshGameObject(componentName + " mesh");
 81
 18882            if (currentMesh == null)
 83            {
 16384                currentMesh = GenerateGeometry();
 85            }
 86
 18887            MeshFilter meshFilter = entity.meshRootGameObject.AddComponent<MeshFilter>();
 18888            MeshRenderer meshRenderer = entity.meshRootGameObject.AddComponent<MeshRenderer>();
 89
 18890            entity.meshesInfo.renderers = new Renderer[] { meshRenderer };
 18891            entity.meshesInfo.currentShape = this;
 92
 18893            meshFilter.sharedMesh = currentMesh;
 94
 18895            if (Configuration.ParcelSettings.VISUAL_LOADING_ENABLED)
 96            {
 197                MaterialTransitionController transition = entity.meshRootGameObject.AddComponent<MaterialTransitionContr
 198                Material finalMaterial = Utils.EnsureResourcesMaterial("Materials/Default");
 199                transition.delay = 0;
 1100                transition.useHologram = false;
 1101                transition.fadeThickness = 20;
 1102                transition.OnDidFinishLoading(finalMaterial);
 103
 3104                transition.onFinishedLoading += () => { OnShapeFinishedLoading(entity); };
 105            }
 106            else
 107            {
 187108                meshRenderer.sharedMaterial = Utils.EnsureResourcesMaterial("Materials/Default");
 109            }
 110
 188111            visibilityDirty = true;
 188112            collisionsDirty = true;
 188113            UpdateRenderer(entity);
 188114            OnShapeFinishedLoading(entity);
 188115            AddRendereableToDataStore(entity);
 188116        }
 117
 118
 119        async UniTaskVoid OnShapeFinishedLoading(IDCLEntity entity)
 120        {
 121            // We need to wait for a frame so that MaterialTransitionController has been destroyed.
 189122            await UniTask.Yield();
 123
 189124            entity.OnShapeUpdated?.Invoke(entity);
 189125            DCL.Environment.i.world.sceneBoundsChecker?.AddEntityToBeChecked(entity);
 189126        }
 127
 128        void OnShapeDetached(IDCLEntity entity)
 129        {
 144130            if (entity == null || entity.meshRootGameObject == null)
 0131                return;
 132
 144133            if (attachedEntities.Count == 0)
 134            {
 119135                DestroyGeometry();
 119136                Utils.CleanMaterials(entity.meshRootGameObject.GetComponent<Renderer>());
 119137                currentMesh = null;
 138            }
 139
 144140            Utils.SafeDestroy(entity.meshRootGameObject);
 144141            entity.meshesInfo.CleanReferences();
 142
 144143            RemoveRendereableFromDataStore(entity);
 144144        }
 145
 146        public override IEnumerator ApplyChanges(BaseModel newModelRaw)
 147        {
 244148            var newModel = (T) newModelRaw;
 149
 244150            if (previousModel != null)
 151            {
 71152                visibilityDirty = newModel.visible != previousModel.visible;
 71153                collisionsDirty = newModel.withCollisions != previousModel.withCollisions || newModel.isPointerBlocker !
 154            }
 155
 244156            bool shouldGenerateMesh = ShouldGenerateNewMesh(previousModel);
 157
 158            //NOTE(Brian): Only generate meshes here if they already are attached to something.
 159            //             Otherwise, the mesh will be created on the OnShapeAttached.
 244160            if (attachedEntities.Count > 0)
 161            {
 60162                using (var iterator = attachedEntities.GetEnumerator())
 163                {
 136164                    while (iterator.MoveNext())
 165                    {
 76166                        var entity = iterator.Current;
 76167                        RemoveRendereableFromDataStore(entity);
 168                    }
 60169                }
 170
 60171                if (shouldGenerateMesh)
 172                {
 6173                    DestroyGeometry();
 6174                    currentMesh = GenerateGeometry();
 175                }
 176
 60177                using (var iterator = attachedEntities.GetEnumerator())
 178                {
 60179                    bool cachedVisibilityDirty = visibilityDirty;
 60180                    bool cachedCollisionDirty = collisionsDirty;
 136181                    while (iterator.MoveNext())
 182                    {
 183                        //NOTE(Alex): Since UpdateRenderer updates the dirty flags as well we have to make sure every en
 184                        //            gets updated accordingly to the original flags.
 76185                        visibilityDirty = cachedVisibilityDirty;
 76186                        collisionsDirty = cachedCollisionDirty;
 187
 76188                        var entity = iterator.Current;
 76189                        UpdateRenderer(entity, newModel);
 190
 76191                        entity.OnShapeUpdated?.Invoke(entity);
 192                    }
 60193                }
 194
 60195                using (var iterator = attachedEntities.GetEnumerator())
 196                {
 136197                    while (iterator.MoveNext())
 198                    {
 76199                        var entity = iterator.Current;
 76200                        AddRendereableToDataStore(entity);
 201                    }
 60202                }
 203            }
 204
 244205            previousModel = newModel;
 244206            return null;
 207        }
 208
 209        public override void AttachTo(IDCLEntity entity, System.Type overridenAttachedType = null)
 210        {
 188211            if (attachedEntities.Contains(entity))
 0212                return;
 213
 188214            base.AttachTo(entity);
 188215        }
 216
 113217        public override bool IsVisible() { return cachedModel.visible; }
 218
 137219        public override bool HasCollisions() { return cachedModel.withCollisions; }
 220
 0221        protected virtual bool ShouldGenerateNewMesh(BaseShape.Model newModel) { return true; }
 222
 223        private void RemoveRendereableFromDataStore(IDCLEntity entity)
 224        {
 408225            if (!attachedRendereables.ContainsKey(entity))
 188226                return;
 227
 220228            DataStore.i.sceneWorldObjects.RemoveRendereable(entity.scene.sceneData.id, attachedRendereables[entity]);
 220229            attachedRendereables.Remove(entity);
 220230        }
 231
 232        private void AddRendereableToDataStore(IDCLEntity entity)
 233        {
 264234            if (attachedRendereables.ContainsKey(entity))
 0235                return;
 236
 264237            int triangleCount = currentMesh.triangles.Length;
 238
 264239            var newRendereable =
 240                new Rendereable()
 241                {
 242                    container = entity.meshRootGameObject,
 243                    totalTriangleCount = triangleCount,
 244                    meshes = new HashSet<Mesh>() { currentMesh },
 245                    meshToTriangleCount = new Dictionary<Mesh, int>() { { currentMesh, triangleCount } }
 246                };
 247
 264248            newRendereable.renderers = MeshesInfoUtils.ExtractUniqueRenderers(entity.meshRootGameObject);
 264249            newRendereable.ownerId = entity.entityId;
 250
 264251            attachedRendereables.Add(entity, newRendereable);
 264252            DataStore.i.sceneWorldObjects.AddRendereable(entity.scene.sceneData.id, newRendereable);
 264253        }
 254    }
 255}