< 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:116
Uncovered lines:7
Coverable lines:123
Total lines:262
Line coverage:94.3% (116 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    {
 13        private const string PARAMETRIZED_SHAPE_TAG = "FromParametrized";
 14
 17615        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        {
 4726            if (currentMesh == null)
 027                return;
 28
 4729            Object.Destroy(currentMesh);
 4730            currentMesh = null;
 4731        }
 32
 191333        public Mesh currentMesh { get; protected set; }
 34        private Model previousModel;
 35        private Model cachedModel;
 36
 17637        public ParametrizedShape()
 38        {
 17639            OnAttach += OnShapeAttached;
 17640            OnDetach += OnShapeDetached;
 17641        }
 42
 43        public override void UpdateFromModel(BaseModel newModel)
 44        {
 24745            cachedModel = (Model) newModel;
 24746            base.UpdateFromModel(newModel);
 24747        }
 48
 49        void UpdateRenderer(IDCLEntity entity, Model model = null)
 50        {
 26751            if (model == null)
 19152                model = (T) this.model;
 53
 26754            if (visibilityDirty)
 55            {
 22656                bool shouldBeVisible = model.visible;
 22657                if (!DataStore.i.debugConfig.isDebugMode.Get())
 21558                    shouldBeVisible &= entity.isInsideSceneBoundaries;
 59
 22660                ConfigureVisibility(entity.meshRootGameObject, shouldBeVisible, entity.meshesInfo.renderers);
 22661                visibilityDirty = false;
 62            }
 63
 26764            if (collisionsDirty)
 65            {
 21466                CollidersManager.i.ConfigureColliders(entity.meshRootGameObject, model.withCollisions && entity.isInside
 21467                collisionsDirty = false;
 68            }
 69
 26770            if (entity.meshesInfo.meshFilters.Length > 0 && entity.meshesInfo.meshFilters[0].sharedMesh != currentMesh)
 71            {
 372                entity.meshesInfo.UpdateExistingMeshAtIndex(currentMesh, 0);
 73            }
 74
 26775            Environment.i.world.sceneBoundsChecker?.AddEntityToBeChecked(entity);
 26776        }
 77
 78        void OnShapeAttached(IDCLEntity entity)
 79        {
 19180            if (entity == null)
 081                return;
 82
 83            // First we remove the old rendereable, then we compute and add the new one.
 19184            RemoveRendereableFromDataStore(entity);
 85
 19186            entity.EnsureMeshGameObject(componentName + " mesh");
 87
 19188            if (currentMesh == null)
 89            {
 16690                currentMesh = GenerateGeometry();
 91            }
 92
 19193            MeshFilter meshFilter = entity.meshRootGameObject.AddComponent<MeshFilter>();
 19194            MeshRenderer meshRenderer = entity.meshRootGameObject.AddComponent<MeshRenderer>();
 95
 19196            entity.meshesInfo.OverrideRenderers( new Renderer[] { meshRenderer });
 19197            entity.meshesInfo.currentShape = this;
 98
 19199            meshFilter.sharedMesh = currentMesh;
 191100            meshFilter.gameObject.tag = PARAMETRIZED_SHAPE_TAG;
 101
 191102            if (Configuration.ParcelSettings.VISUAL_LOADING_ENABLED)
 103            {
 1104                MaterialTransitionController transition = entity.meshRootGameObject.AddComponent<MaterialTransitionContr
 1105                Material finalMaterial = Utils.EnsureResourcesMaterial("Materials/Default");
 1106                transition.delay = 0;
 1107                transition.useHologram = false;
 1108                transition.fadeThickness = 20;
 1109                transition.OnDidFinishLoading(finalMaterial);
 110
 3111                transition.onFinishedLoading += () => { OnShapeFinishedLoading(entity); };
 112            }
 113            else
 114            {
 190115                meshRenderer.sharedMaterial = Utils.EnsureResourcesMaterial("Materials/Default");
 116            }
 117
 191118            visibilityDirty = true;
 191119            collisionsDirty = true;
 191120            UpdateRenderer(entity);
 191121            OnShapeFinishedLoading(entity);
 191122            AddRendereableToDataStore(entity);
 191123        }
 124
 125
 126        async UniTaskVoid OnShapeFinishedLoading(IDCLEntity entity)
 127        {
 128            // We need to wait for a frame so that MaterialTransitionController has been destroyed.
 192129            await UniTask.Yield();
 130
 192131            entity.OnShapeUpdated?.Invoke(entity);
 192132            DCL.Environment.i.world.sceneBoundsChecker?.AddEntityToBeChecked(entity);
 192133        }
 134
 135        void OnShapeDetached(IDCLEntity entity)
 136        {
 147137            if (entity == null || entity.meshRootGameObject == null)
 0138                return;
 139
 147140            if (attachedEntities.Count == 0)
 141            {
 122142                DestroyGeometry();
 122143                Utils.CleanMaterials(entity.meshRootGameObject.GetComponent<Renderer>());
 122144                currentMesh = null;
 145            }
 146
 147147            Utils.SafeDestroy(entity.meshRootGameObject);
 147148            entity.meshesInfo.CleanReferences();
 149
 147150            RemoveRendereableFromDataStore(entity);
 147151        }
 152
 153        public override IEnumerator ApplyChanges(BaseModel newModelRaw)
 154        {
 247155            var newModel = (T) newModelRaw;
 156
 247157            if (previousModel != null)
 158            {
 71159                visibilityDirty = newModel.visible != previousModel.visible;
 71160                collisionsDirty = newModel.withCollisions != previousModel.withCollisions || newModel.isPointerBlocker !
 161            }
 162
 247163            bool shouldGenerateMesh = ShouldGenerateNewMesh(previousModel);
 164
 165            //NOTE(Brian): Only generate meshes here if they already are attached to something.
 166            //             Otherwise, the mesh will be created on the OnShapeAttached.
 247167            if (attachedEntities.Count > 0)
 168            {
 60169                using (var iterator = attachedEntities.GetEnumerator())
 170                {
 136171                    while (iterator.MoveNext())
 172                    {
 76173                        var entity = iterator.Current;
 76174                        RemoveRendereableFromDataStore(entity);
 175                    }
 60176                }
 177
 60178                if (shouldGenerateMesh)
 179                {
 6180                    DestroyGeometry();
 6181                    currentMesh = GenerateGeometry();
 182                }
 183
 60184                using (var iterator = attachedEntities.GetEnumerator())
 185                {
 60186                    bool cachedVisibilityDirty = visibilityDirty;
 60187                    bool cachedCollisionDirty = collisionsDirty;
 136188                    while (iterator.MoveNext())
 189                    {
 190                        //NOTE(Alex): Since UpdateRenderer updates the dirty flags as well we have to make sure every en
 191                        //            gets updated accordingly to the original flags.
 76192                        visibilityDirty = cachedVisibilityDirty;
 76193                        collisionsDirty = cachedCollisionDirty;
 194
 76195                        var entity = iterator.Current;
 76196                        UpdateRenderer(entity, newModel);
 197
 76198                        entity.OnShapeUpdated?.Invoke(entity);
 199                    }
 60200                }
 201
 60202                using (var iterator = attachedEntities.GetEnumerator())
 203                {
 136204                    while (iterator.MoveNext())
 205                    {
 76206                        var entity = iterator.Current;
 76207                        AddRendereableToDataStore(entity);
 208                    }
 60209                }
 210            }
 211
 247212            previousModel = newModel;
 247213            return null;
 214        }
 215
 216        public override void AttachTo(IDCLEntity entity, System.Type overridenAttachedType = null)
 217        {
 191218            if (attachedEntities.Contains(entity))
 0219                return;
 220
 191221            base.AttachTo(entity);
 191222        }
 223
 118224        public override bool IsVisible() { return cachedModel.visible; }
 225
 153226        public override bool HasCollisions() { return cachedModel.withCollisions; }
 227
 0228        protected virtual bool ShouldGenerateNewMesh(BaseShape.Model newModel) { return true; }
 229
 230        private void RemoveRendereableFromDataStore(IDCLEntity entity)
 231        {
 414232            if (!attachedRendereables.ContainsKey(entity))
 191233                return;
 234
 223235            DataStore.i.sceneWorldObjects.RemoveRendereable(entity.scene.sceneData.sceneNumber, attachedRendereables[ent
 223236            attachedRendereables.Remove(entity);
 223237        }
 238
 239        private void AddRendereableToDataStore(IDCLEntity entity)
 240        {
 267241            if (attachedRendereables.ContainsKey(entity))
 0242                return;
 243
 267244            int triangleCount = currentMesh.triangles.Length;
 245
 267246            var newRendereable =
 247                new Rendereable()
 248                {
 249                    container = entity.meshRootGameObject,
 250                    totalTriangleCount = triangleCount,
 251                    meshes = new HashSet<Mesh>() { currentMesh },
 252                    meshToTriangleCount = new Dictionary<Mesh, int>() { { currentMesh, triangleCount } }
 253                };
 254
 267255            newRendereable.renderers = MeshesInfoUtils.ExtractUniqueRenderers(entity.meshRootGameObject);
 267256            newRendereable.ownerId = entity.entityId;
 257
 267258            attachedRendereables.Add(entity, newRendereable);
 267259            DataStore.i.sceneWorldObjects.AddRendereable(entity.scene.sceneData.sceneNumber, newRendereable);
 267260        }
 261    }
 262}