< Summary

Class:Builder.DCLBuilderObjectSelector
Assembly:Builder
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Builder/Scripts/DCLBuilderObjectSelector.cs
Covered lines:44
Uncovered lines:164
Coverable lines:208
Total lines:466
Line coverage:21.1% (44 of 208)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
DCLBuilderObjectSelector()0%110100%
Awake()0%110100%
OnDestroy()0%220100%
OnEnable()0%220100%
OnDisable()0%110100%
Update()0%15.555025%
OnMouseDown(...)0%1101000%
OnMouseUp(...)0%72800%
OnResetObject()0%6200%
OnEntityAdded(...)0%220100%
OnEntityRemoved(...)0%12300%
OnSceneChanged(...)0%110100%
OnBuilderSelectEntity(...)0%30500%
OnGizmoTransform(...)0%2100%
OnGizmoTransformEnded(...)0%6200%
OnObjectsDrag()0%2100%
OnObjectsDragEnd()0%6200%
CanSelect(...)0%2100%
MarkSelected(...)0%12300%
Select(...)0%20400%
Deselect(...)0%20400%
DeselectAll()0%6200%
OnPreviewModeChanged(...)0%2100%
SetLastPressedEntity(...)0%2100%
ProcessEntityPressed(...)0%6200%
SelectionParentCreate()0%110100%
SelectionParentReset()0%1101000%
SelectionParentAddEntity(...)0%2100%
SelectionParentAddEntity(...)0%2100%
SelectionParentRemoveEntity(...)0%2100%
SelectionParentRemoveEntity(...)0%2100%
SelectionParentRemoveAllEntities()0%6200%
SelectionParentHasChild(...)0%2100%
CompareSelectionHit(...)0%56700%
IsGizmoHit(...)0%2100%
IsEntityHitAndSelected(...)0%6200%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Builder/Scripts/DCLBuilderObjectSelector.cs

#LineLine coverage
 1using UnityEngine;
 2using DCL.Controllers;
 3using Builder.Gizmos;
 4using System.Collections.Generic;
 5
 6namespace Builder
 7{
 8    public class DCLBuilderObjectSelector : MonoBehaviour
 9    {
 10        const float DRAGGING_THRESHOLD_TIME = 0.25f;
 11
 12        public DCLBuilderRaycast builderRaycast;
 13        public DCLBuilderGizmoManager gizmosManager;
 14
 15        public delegate void EntitySelectedDelegate(EditableEntity entity, string gizmoType);
 16
 17        public delegate void EntityDeselectedDelegate(EditableEntity entity);
 18
 19        public delegate void EntitySelectedListChangedDelegate(Transform selectionParent, List<EditableEntity> selectedE
 20
 21        public static event EntitySelectedDelegate OnMarkObjectSelected;
 22        public static event EntitySelectedDelegate OnSelectedObject;
 23        public static event EntityDeselectedDelegate OnDeselectedObject;
 24        public static event System.Action OnNoObjectSelected;
 25        public static event EntitySelectedListChangedDelegate OnSelectedObjectListChanged;
 26        public static event System.Action<DCLBuilderEntity, Vector3> OnEntityPressed;
 27        public static event System.Action<DCLBuilderGizmoAxis> OnGizmosAxisPressed;
 28
 029        public Transform selectedEntitiesParent { private set; get; }
 30
 19931        private Dictionary<string, DCLBuilderEntity> entities = new Dictionary<string, DCLBuilderEntity>();
 19932        private List<EditableEntity> selectedEntities = new List<EditableEntity>();
 19933        private EntityPressedInfo lastPressedEntityInfo = new EntityPressedInfo();
 34        private bool isDirty = false;
 35        private bool isSelectionTransformed = false;
 36
 37        private float groundClickTime = 0;
 38
 39        private bool isGameObjectActive = false;
 40
 41        private ParcelScene currentScene;
 42
 43        private void Awake()
 44        {
 145            DCLBuilderBridge.OnPreviewModeChanged += OnPreviewModeChanged;
 146            SelectionParentCreate();
 147        }
 48
 49        private void OnDestroy()
 50        {
 151            if (selectedEntitiesParent != null)
 152                Destroy(selectedEntitiesParent.gameObject);
 53
 154            DCLBuilderBridge.OnPreviewModeChanged -= OnPreviewModeChanged;
 155        }
 56
 57        private void OnEnable()
 58        {
 159            if (!isGameObjectActive)
 60            {
 161                DCLBuilderInput.OnMouseDown += OnMouseDown;
 162                DCLBuilderInput.OnMouseUp += OnMouseUp;
 163                DCLBuilderBridge.OnResetObject += OnResetObject;
 164                DCLBuilderBridge.OnEntityAdded += OnEntityAdded;
 165                DCLBuilderBridge.OnEntityRemoved += OnEntityRemoved;
 166                DCLBuilderBridge.OnSceneChanged += OnSceneChanged;
 167                DCLBuilderBridge.OnBuilderSelectEntity += OnBuilderSelectEntity;
 168                DCLBuilderGizmoManager.OnGizmoTransformObject += OnGizmoTransform;
 169                DCLBuilderGizmoManager.OnGizmoTransformObjectEnd += OnGizmoTransformEnded;
 170                DCLBuilderObjectDragger.OnDraggingObject += OnObjectsDrag;
 171                DCLBuilderObjectDragger.OnDraggingObjectEnd += OnObjectsDragEnd;
 72            }
 73
 174            isGameObjectActive = true;
 175        }
 76
 77        private void OnDisable()
 78        {
 179            isGameObjectActive = false;
 180            DCLBuilderInput.OnMouseDown -= OnMouseDown;
 181            DCLBuilderInput.OnMouseUp -= OnMouseUp;
 182            DCLBuilderBridge.OnResetObject -= OnResetObject;
 183            DCLBuilderBridge.OnEntityAdded -= OnEntityAdded;
 184            DCLBuilderBridge.OnEntityRemoved -= OnEntityRemoved;
 185            DCLBuilderBridge.OnSceneChanged -= OnSceneChanged;
 186            DCLBuilderBridge.OnBuilderSelectEntity -= OnBuilderSelectEntity;
 187            DCLBuilderGizmoManager.OnGizmoTransformObject -= OnGizmoTransform;
 188            DCLBuilderGizmoManager.OnGizmoTransformObjectEnd -= OnGizmoTransformEnded;
 189            DCLBuilderObjectDragger.OnDraggingObject -= OnObjectsDrag;
 190            DCLBuilderObjectDragger.OnDraggingObjectEnd -= OnObjectsDragEnd;
 191        }
 92
 93        private void Update()
 94        {
 1195            if (!isDirty)
 96            {
 1197                return;
 98            }
 99
 0100            isDirty = false;
 0101            SelectionParentReset();
 0102            OnSelectedObjectListChanged?.Invoke(selectedEntitiesParent, selectedEntities);
 0103            if (selectedEntities.Count == 0)
 104            {
 0105                OnNoObjectSelected?.Invoke();
 106            }
 0107        }
 108
 109        private void OnMouseDown(int buttonId, Vector3 mousePosition)
 110        {
 0111            if (buttonId != 0)
 112            {
 0113                return;
 114            }
 115
 0116            bool gizmoOrEntityPressed = false;
 117
 118            RaycastHit hit;
 0119            if (builderRaycast.Raycast(mousePosition, builderRaycast.defaultMask | builderRaycast.gizmoMask, out hit, Co
 120            {
 0121                DCLBuilderGizmoAxis gizmosAxis = hit.collider.gameObject.GetComponent<DCLBuilderGizmoAxis>();
 0122                if (gizmosAxis != null)
 123                {
 0124                    OnGizmosAxisPressed?.Invoke(gizmosAxis);
 0125                    gizmoOrEntityPressed = true;
 0126                }
 127                else
 128                {
 0129                    var builderSelectionCollider = hit.collider.gameObject.GetComponent<DCLBuilderSelectionCollider>();
 0130                    DCLBuilderEntity pressedEntity = null;
 131
 0132                    if (builderSelectionCollider != null)
 133                    {
 0134                        pressedEntity = builderSelectionCollider.ownerEntity;
 135                    }
 136
 0137                    if (pressedEntity != null && CanSelect(pressedEntity))
 138                    {
 0139                        SetLastPressedEntity(pressedEntity, hit.point);
 0140                        OnEntityPressed?.Invoke(pressedEntity, hit.point);
 0141                        gizmoOrEntityPressed = true;
 142                    }
 143                }
 144            }
 145
 0146            if (gizmoOrEntityPressed)
 147            {
 0148                groundClickTime = 0;
 0149            }
 150            else
 151            {
 0152                groundClickTime = Time.unscaledTime;
 153            }
 0154        }
 155
 156        private void OnMouseUp(int buttonId, Vector3 mousePosition)
 157        {
 0158            if (buttonId != 0)
 159            {
 0160                return;
 161            }
 162
 0163            if (lastPressedEntityInfo.pressedEntity != null)
 164            {
 165                // NOTE: we only process entity as selected if we are not considering that user was holding mouse button
 0166                if ((Time.unscaledTime - lastPressedEntityInfo.pressedTime) < DRAGGING_THRESHOLD_TIME)
 167                {
 0168                    ProcessEntityPressed(lastPressedEntityInfo.pressedEntity, lastPressedEntityInfo.hitPoint);
 169                }
 170            }
 171
 0172            lastPressedEntityInfo.pressedEntity = null;
 173
 174            // NOTE: deselect all entities if the user click on the ground and it wasn't holding the mouse left button
 0175            if (groundClickTime != 0 && (Time.unscaledTime - groundClickTime) < DRAGGING_THRESHOLD_TIME)
 176            {
 0177                if (selectedEntities != null)
 178                {
 0179                    OnNoObjectSelected?.Invoke();
 180                }
 181            }
 182
 0183            groundClickTime = 0;
 0184        }
 185
 186        private void OnResetObject()
 187        {
 0188            for (int i = 0; i < selectedEntities.Count; i++)
 189            {
 0190                selectedEntities[i].transform.localRotation = Quaternion.identity;
 191            }
 0192        }
 193
 194        private void OnEntityAdded(DCLBuilderEntity entity)
 195        {
 1196            if (!entities.ContainsKey(entity.rootEntity.entityId))
 197            {
 1198                entities.Add(entity.rootEntity.entityId, entity);
 199            }
 1200        }
 201
 202        private void OnEntityRemoved(DCLBuilderEntity entity)
 203        {
 0204            if (selectedEntities.Contains(entity))
 205            {
 0206                Deselect(entity);
 207            }
 208
 0209            if (entities.ContainsKey(entity.rootEntity.entityId))
 210            {
 0211                entities.Remove(entity.rootEntity.entityId);
 212            }
 0213        }
 214
 4215        private void OnSceneChanged(ParcelScene scene) { currentScene = scene; }
 216
 217        private void OnBuilderSelectEntity(string[] entitiesId)
 218        {
 0219            List<EditableEntity> entitiesToDeselect = new List<EditableEntity>(selectedEntities);
 220
 0221            for (int i = 0; i < entitiesId.Length; i++)
 222            {
 0223                if (entities.ContainsKey(entitiesId[i]))
 224                {
 0225                    DCLBuilderEntity entity = entities[entitiesId[i]];
 0226                    if (!SelectionParentHasChild(entity.transform))
 227                    {
 0228                        Select(entity);
 0229                    }
 230                    else
 231                    {
 0232                        entitiesToDeselect.Remove(entity);
 233                    }
 234                }
 235            }
 236
 0237            for (int i = 0; i < entitiesToDeselect.Count; i++)
 238            {
 0239                Deselect(entitiesToDeselect[i]);
 240            }
 0241        }
 242
 0243        private void OnGizmoTransform(string gizmoType) { isSelectionTransformed = true; }
 244
 245        private void OnGizmoTransformEnded(string gizmoType)
 246        {
 0247            if (isSelectionTransformed)
 248            {
 0249                SelectionParentReset();
 250            }
 251
 0252            isSelectionTransformed = false;
 0253        }
 254
 0255        private void OnObjectsDrag() { isSelectionTransformed = true; }
 256
 257        private void OnObjectsDragEnd()
 258        {
 0259            if (isSelectionTransformed)
 260            {
 0261                SelectionParentReset();
 262            }
 263
 0264            isSelectionTransformed = false;
 0265        }
 266
 0267        private bool CanSelect(DCLBuilderEntity entity) { return entity.hasGizmoComponent; }
 268
 269        private void MarkSelected(DCLBuilderEntity entity)
 270        {
 0271            if (entity == null)
 272            {
 0273                return;
 274            }
 275
 0276            OnMarkObjectSelected?.Invoke(entity, gizmosManager.GetSelectedGizmo());
 0277        }
 278
 279        private void Select(DCLBuilderEntity entity)
 280        {
 0281            if (entity == null)
 282            {
 0283                return;
 284            }
 285
 0286            if (!selectedEntities.Contains(entity))
 287            {
 0288                selectedEntities.Add(entity);
 289            }
 290
 0291            SelectionParentAddEntity(entity);
 0292            entity.SetSelectLayer();
 293
 0294            OnSelectedObject?.Invoke(entity, gizmosManager.GetSelectedGizmo());
 0295            isDirty = true;
 0296        }
 297
 298        private void Deselect(EditableEntity entity)
 299        {
 0300            if (entity != null)
 301            {
 0302                SelectionParentRemoveEntity(entity);
 0303                OnDeselectedObject?.Invoke(entity);
 0304                entity.SetDefaultLayer();
 305            }
 306
 0307            if (selectedEntities.Contains(entity))
 308            {
 0309                selectedEntities.Remove(entity);
 310            }
 311
 0312            isDirty = true;
 0313        }
 314
 315        private void DeselectAll()
 316        {
 0317            for (int i = selectedEntities.Count - 1; i >= 0; i--)
 318            {
 0319                Deselect(selectedEntities[i]);
 320            }
 321
 0322            SelectionParentRemoveAllEntities();
 0323        }
 324
 325        private void OnPreviewModeChanged(bool isPreview)
 326        {
 0327            DeselectAll();
 0328            gameObject.SetActive(!isPreview);
 0329        }
 330
 331        private void SetLastPressedEntity(DCLBuilderEntity pressedEntity, Vector3 hitPoint)
 332        {
 0333            lastPressedEntityInfo.pressedEntity = pressedEntity;
 0334            lastPressedEntityInfo.pressedTime = Time.unscaledTime;
 0335            lastPressedEntityInfo.hitPoint = hitPoint;
 0336        }
 337
 338        private void ProcessEntityPressed(DCLBuilderEntity pressedEntity, Vector3 hitPoint)
 339        {
 0340            if (CanSelect(pressedEntity))
 341            {
 0342                MarkSelected(pressedEntity);
 343            }
 0344        }
 345
 2346        private void SelectionParentCreate() { selectedEntitiesParent = new GameObject("BuilderSelectedEntitiesParent").
 347
 348        private void SelectionParentReset()
 349        {
 0350            if (selectedEntitiesParent.childCount == 0)
 351            {
 0352                return;
 353            }
 354
 0355            Transform entitiyTransform = selectedEntitiesParent.GetChild(0);
 0356            Vector3 min = entitiyTransform.position;
 0357            Vector3 max = entitiyTransform.position;
 358
 0359            List<Transform> children = new List<Transform>(selectedEntitiesParent.childCount);
 360
 0361            children.Add(entitiyTransform);
 0362            SelectionParentRemoveEntity(entitiyTransform);
 363
 0364            for (int i = selectedEntitiesParent.childCount - 1; i >= 0; i--)
 365            {
 0366                entitiyTransform = selectedEntitiesParent.GetChild(i);
 0367                if (entitiyTransform.position.x < min.x)
 0368                    min.x = entitiyTransform.position.x;
 0369                if (entitiyTransform.position.y < min.y)
 0370                    min.y = entitiyTransform.position.y;
 0371                if (entitiyTransform.position.z < min.z)
 0372                    min.z = entitiyTransform.position.z;
 0373                if (entitiyTransform.position.x > max.x)
 0374                    max.x = entitiyTransform.position.x;
 0375                if (entitiyTransform.position.y > max.y)
 0376                    max.y = entitiyTransform.position.y;
 0377                if (entitiyTransform.position.z > max.z)
 0378                    max.z = entitiyTransform.position.z;
 379
 0380                children.Add(entitiyTransform);
 0381                SelectionParentRemoveEntity(entitiyTransform);
 382            }
 383
 0384            selectedEntitiesParent.position = min + (max - min) * 0.5f;
 0385            selectedEntitiesParent.localScale = Vector3.one;
 0386            selectedEntitiesParent.rotation = Quaternion.identity;
 387
 0388            for (int i = 0; i < children.Count; i++)
 389            {
 0390                SelectionParentAddEntity(children[i]);
 391            }
 0392        }
 393
 0394        private void SelectionParentAddEntity(DCLBuilderEntity entity) { SelectionParentAddEntity(entity.transform); }
 395
 0396        private void SelectionParentAddEntity(Transform entityTransform) { entityTransform.SetParent(selectedEntitiesPar
 397
 0398        private void SelectionParentRemoveEntity(EditableEntity entity) { SelectionParentRemoveEntity(entity.transform);
 399
 0400        private void SelectionParentRemoveEntity(Transform entityTransform) { entityTransform.SetParent(currentScene.tra
 401
 402        private void SelectionParentRemoveAllEntities()
 403        {
 0404            for (int i = selectedEntitiesParent.childCount - 1; i >= 0; i--)
 405            {
 0406                SelectionParentRemoveEntity(selectedEntitiesParent.GetChild(i));
 407            }
 0408        }
 409
 0410        private bool SelectionParentHasChild(Transform transform) { return transform.parent == selectedEntitiesParent; }
 411
 412        private RaycastHit CompareSelectionHit(RaycastHit[] hits)
 413        {
 0414            RaycastHit closestHit = hits[0];
 0415            bool isHitASelectedObject = IsEntityHitAndSelected(closestHit);
 416
 0417            if (IsGizmoHit(closestHit)) // Gizmos has always priority
 418            {
 0419                return closestHit;
 420            }
 421
 422            RaycastHit hit;
 0423            for (int i = 1; i < hits.Length; i++)
 424            {
 0425                hit = hits[i];
 0426                if (IsGizmoHit(hit)) // Gizmos has always priority
 427                {
 0428                    return hit;
 429                }
 430
 0431                if (hit.distance < closestHit.distance)
 432                {
 0433                    isHitASelectedObject = IsEntityHitAndSelected(hit);
 0434                    closestHit = hit;
 0435                }
 0436                else if (hit.distance == closestHit.distance && !isHitASelectedObject)
 437                {
 0438                    isHitASelectedObject = IsEntityHitAndSelected(hit);
 0439                    closestHit = hit;
 440                }
 441            }
 442
 0443            return closestHit;
 444        }
 445
 0446        private bool IsGizmoHit(RaycastHit hit) { return hit.collider.gameObject.GetComponent<DCLBuilderGizmoAxis>() != 
 447
 448        private bool IsEntityHitAndSelected(RaycastHit hit)
 449        {
 0450            var collider = hit.collider.gameObject.GetComponent<DCLBuilderSelectionCollider>();
 0451            if (collider != null)
 452            {
 0453                return SelectionParentHasChild(collider.ownerEntity.transform);
 454            }
 455
 0456            return false;
 457        }
 458
 459        private class EntityPressedInfo
 460        {
 461            public DCLBuilderEntity pressedEntity;
 462            public float pressedTime;
 463            public Vector3 hitPoint;
 464        }
 465    }
 466}