< Summary

Class:ECSSystems.PointerInputSystem.ECSPointerInputSystem
Assembly:ECS7Plugin.Systems.PointerInput
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/DCLPlugins/ECS7/Systems/PointerInputSystem/ECSPointerInputSystem.cs
Covered lines:101
Uncovered lines:1
Coverable lines:102
Total lines:342
Line coverage:99% (101 of 102)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
CreateSystem(...)0%110100%
Update(...)0%16160100%
IsColliderDifferent(...)0%440100%
IsColliderMissing(...)0%220100%
IsColliderAvailable(...)0%220100%
HandleColliderChanged(...)0%220100%
HandleMissingCollider(...)0%220100%
HandleAvailableCollider(...)0%110100%
BroadcastInputResultEvent(...)0%440100%
AddInputResultEvent(...)0%110100%
GetEntityWithCollider(...)0%3.023087.5%
ShowHoverTooltips(...)0%18180100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/DCLPlugins/ECS7/Systems/PointerInputSystem/ECSPointerInputSystem.cs

#LineLine coverage
 1using DCL;
 2using DCL.Controllers;
 3using DCL.ECS7.InternalComponents;
 4using DCL.ECSComponents;
 5using DCL.ECSRuntime;
 6using DCL.Interface;
 7using System;
 8using System.Collections.Generic;
 9using UnityEngine;
 10
 11namespace ECSSystems.PointerInputSystem
 12{
 13    public static class ECSPointerInputSystem
 14    {
 15        private class State
 16        {
 17            public IInternalECSComponent<InternalColliders> pointerColliderComponent;
 18            public IInternalECSComponent<InternalInputEventResults> inputResultComponent;
 19            public ECSComponent<PBPointerEvents> pointerEvents;
 20            public DataStore_ECS7 dataStoreEcs7;
 21            public EntityInput lastHoverFeedback;
 22            public IWorldState worldState;
 23            public IECSInteractionHoverCanvas interactionHoverCanvas;
 24            public bool[] inputActionState;
 25        }
 26
 27        private class EntityInput
 28        {
 29            public long entityId;
 30
 31            public IParcelScene scene;
 32            public int sceneNumber;
 33
 34            public bool hasValue;
 35        }
 36
 37        public static Action CreateSystem(
 38            IInternalECSComponent<InternalColliders> pointerColliderComponent,
 39            IInternalECSComponent<InternalInputEventResults> inputResultComponent,
 40            ECSComponent<PBPointerEvents> pointerEvents,
 41            IECSInteractionHoverCanvas interactionHoverCanvas,
 42            IWorldState worldState,
 43            DataStore_ECS7 dataStoreEcs)
 44        {
 1945            var state = new State()
 46            {
 47                pointerColliderComponent = pointerColliderComponent,
 48                inputResultComponent = inputResultComponent,
 49                pointerEvents = pointerEvents,
 50                worldState = worldState,
 51                interactionHoverCanvas = interactionHoverCanvas,
 52                dataStoreEcs7 = dataStoreEcs,
 53                lastHoverFeedback = new EntityInput() { hasValue = false },
 54                inputActionState = new bool[Enum.GetValues(typeof(WebInterface.ACTION_BUTTON)).Length]
 55            };
 5756            return () => Update(state);
 57        }
 58
 59        private static void Update(State state)
 60        {
 61            // Retrieve the last raycast hit
 3862            bool doesRaycastHit = state.dataStoreEcs7.lastPointerRayHit.hasValue && state.dataStoreEcs7.lastPointerRayHi
 3863            DataStore_ECS7.RaycastEvent.Hit raycastHit = state.dataStoreEcs7.lastPointerRayHit.hit;
 3864            Ray raycastRay = state.dataStoreEcs7.lastPointerRayHit.ray;
 65
 66            // Get the collider that the raycast hit
 3867            IECSReadOnlyComponentData<InternalColliders> colliderData = doesRaycastHit
 68                ? state.pointerColliderComponent
 69                       .GetEntityWithCollider(raycastHit.collider)
 70                : null;
 3871            IParcelScene colliderScene = colliderData != null ? colliderData.scene : null;
 72
 3873            bool isAnyButtonDown = false;
 74            bool hasAnyButtonChangedItsState = false;
 75            bool hasHoverEventEmitted = false;
 76
 3877            var inputActionEnum = (WebInterface.ACTION_BUTTON[]) Enum.GetValues(typeof(WebInterface.ACTION_BUTTON));
 78
 79            // Emit command for button states
 3880            var curState = state.dataStoreEcs7.inputActionState;
 3881            var prevState = state.inputActionState;
 114082            for (int i = 0; i < state.dataStoreEcs7.inputActionState.Length; i++)
 83            {
 53284                isAnyButtonDown |= curState[i];
 85
 53286                if (curState[i] != prevState[i])
 87                {
 1888                    PointerEventType pointerEventType = curState[i] ? PointerEventType.PetDown : PointerEventType.PetUp;
 1889                    InputAction inputAction = (InputAction)inputActionEnum[i];
 90
 1891                    if (colliderData != null)
 92                    {
 1593                        AddInputResultEvent(
 94                            state,
 95                            inputAction,
 96                            colliderData.scene,
 97                            colliderData.entity.entityId,
 98                            raycastRay,
 99                            raycastHit,
 100                            pointerEventType
 101                        );
 102                    }
 103
 18104                    BroadcastInputResultEvent(
 105                        state,
 106                        inputAction,
 107                        -1,
 108                        raycastRay,
 109                        raycastHit,
 110                        pointerEventType,
 111                        colliderScene
 112                    );
 113
 114                    // update
 18115                    prevState[i] = curState[i];
 116                }
 117            }
 118
 119            // Check if the hovered entity has changed with three options:
 120            // 1) We were hitting a collider A and now we're hitting a collider B
 38121            if (IsColliderDifferent(state, colliderData)) {
 2122                HandleColliderChanged(state, colliderData);
 123
 124            // 2) We were hitting a collider A and now we're not hitting anything
 36125            } else if (IsColliderMissing(state, colliderData))
 126            {
 2127                HandleMissingCollider(state);
 128
 129            // 3) We were not hitting anything and now we're hitting collider A
 34130            } else if (IsColliderAvailable(state, colliderData)) {
 16131                HandleAvailableCollider(state, colliderData);
 132            }
 133
 38134            if (colliderData != null)
 135            {
 22136                var hoverEvents = state.pointerEvents.GetPointerEventsForEntity(colliderData.scene, colliderData.entity)
 22137                state.interactionHoverCanvas.ShowHoverTooltips(hoverEvents, curState, raycastHit.distance, isAnyButtonDo
 138            }
 38139        }
 140        private static bool IsColliderDifferent(State state, IECSReadOnlyComponentData<InternalColliders> colliderData)
 141        {
 38142            return colliderData != null && // current collider
 143                   state.lastHoverFeedback.hasValue && // previous collider
 144                   (state.lastHoverFeedback.entityId != colliderData.entity.entityId ||
 145                    state.lastHoverFeedback.sceneNumber != colliderData.scene.sceneData.sceneNumber);
 146        }
 147
 148        private static bool IsColliderMissing(State state, IECSReadOnlyComponentData<InternalColliders> colliderData)
 149        {
 36150            return colliderData == null && state.lastHoverFeedback.hasValue;
 151        }
 152
 153        private static bool IsColliderAvailable(State state, IECSReadOnlyComponentData<InternalColliders> colliderData)
 154        {
 34155            return colliderData != null && !state.lastHoverFeedback.hasValue;
 156        }
 157
 158        private static void HandleColliderChanged(State state, IECSReadOnlyComponentData<InternalColliders> colliderData
 2159            DataStore_ECS7.RaycastEvent.Hit raycastHit = state.dataStoreEcs7.lastPointerRayHit.hit;
 2160            Ray raycastRay = state.dataStoreEcs7.lastPointerRayHit.ray;
 161
 2162            if (state.worldState.ContainsScene(state.lastHoverFeedback.sceneNumber))
 163            {
 2164                AddInputResultEvent(
 165                    state,
 166                    InputAction.IaAny,
 167                    state.lastHoverFeedback.scene,
 168                    state.lastHoverFeedback.entityId,
 169                    raycastRay,
 170                    raycastHit,
 171                    PointerEventType.PetHoverLeave
 172                );
 173            }
 174
 2175            AddInputResultEvent(
 176                state,
 177                InputAction.IaAny,
 178                colliderData.scene,
 179                colliderData.entity.entityId,
 180                raycastRay,
 181                raycastHit,
 182                PointerEventType.PetHoverEnter
 183            );
 184
 2185            state.interactionHoverCanvas.Hide();
 186
 2187            state.lastHoverFeedback.hasValue = true;
 2188            state.lastHoverFeedback.sceneNumber = colliderData.scene.sceneData.sceneNumber;
 2189            state.lastHoverFeedback.scene = colliderData.scene;
 2190            state.lastHoverFeedback.entityId = colliderData.entity.entityId;
 2191        }
 192
 193        private static void HandleMissingCollider(State state) {
 2194            DataStore_ECS7.RaycastEvent.Hit raycastHit = state.dataStoreEcs7.lastPointerRayHit.hit;
 2195            Ray raycastRay = state.dataStoreEcs7.lastPointerRayHit.ray;
 196
 2197            if (state.worldState.ContainsScene(state.lastHoverFeedback.sceneNumber))
 198            {
 2199                AddInputResultEvent(
 200                    state,
 201                    InputAction.IaAny,
 202                    state.lastHoverFeedback.scene,
 203                    state.lastHoverFeedback.entityId,
 204                    raycastRay,
 205                    raycastHit,
 206                    PointerEventType.PetHoverLeave
 207                );
 208            }
 209
 2210            state.interactionHoverCanvas.Hide();
 2211            state.lastHoverFeedback.hasValue = false;
 2212        }
 213
 214        private static void  HandleAvailableCollider(State state, IECSReadOnlyComponentData<InternalColliders> colliderD
 16215            DataStore_ECS7.RaycastEvent.Hit raycastHit = state.dataStoreEcs7.lastPointerRayHit.hit;
 16216            Ray raycastRay = state.dataStoreEcs7.lastPointerRayHit.ray;
 217
 16218            AddInputResultEvent(
 219                state,
 220                InputAction.IaAny,
 221                colliderData.scene,
 222                colliderData.entity.entityId,
 223                raycastRay,
 224                raycastHit,
 225                PointerEventType.PetHoverEnter
 226            );
 227
 16228            state.lastHoverFeedback.hasValue = true;
 16229            state.lastHoverFeedback.sceneNumber = colliderData.scene.sceneData.sceneNumber;
 16230            state.lastHoverFeedback.scene = colliderData.scene;
 16231            state.lastHoverFeedback.entityId = colliderData.entity.entityId;
 16232        }
 233
 234        private static void BroadcastInputResultEvent(State state, InputAction buttonId,
 235            long entityId, Ray ray, DataStore_ECS7.RaycastEvent.Hit raycastHit, PointerEventType pointerEventType, IParc
 236        {
 18237            IReadOnlyList<IParcelScene> loadedScenes = state.dataStoreEcs7.scenes;
 72238            for (int i = 0; i < loadedScenes.Count; i++)
 239            {
 18240                if (loadedScenes[i] != skipScene && loadedScenes[i].crdtExecutor != null)
 241                {
 5242                    AddInputResultEvent(state, buttonId, loadedScenes[i], entityId, ray, raycastHit, pointerEventType);
 243                }
 244            }
 18245        }
 246
 247        private static void AddInputResultEvent(State state, InputAction buttonId, IParcelScene scene,
 248            long entityId, Ray ray, DataStore_ECS7.RaycastEvent.Hit raycastHit, PointerEventType pointerEventType)
 249        {
 42250            raycastHit.point = WorldStateUtils.ConvertUnityToScenePosition(raycastHit.point, scene);
 42251            ray.origin = WorldStateUtils.ConvertUnityToScenePosition(ray.origin, scene);
 252
 42253            state.inputResultComponent.AddEvent(scene, new InternalInputEventResults.EventData()
 254            {
 255                button = buttonId,
 256                hit = ProtoConvertUtils.ToPBRaycasHit(entityId, null,
 257                    ray, raycastHit.distance, raycastHit.point, raycastHit.normal, entityId != -1),
 258                type = pointerEventType
 259            });
 42260        }
 261
 262        private static IECSReadOnlyComponentData<InternalColliders> GetEntityWithCollider(
 263            this IInternalECSComponent<InternalColliders> pointerColliderComponent,
 264            Collider collider)
 265        {
 22266            var collidersData = pointerColliderComponent.GetForAll();
 56267            for (int i = 0; i < collidersData.Count; i++)
 268            {
 28269                var colliderData = collidersData[i].value;
 28270                if (colliderData.model.colliders.Contains(collider))
 271                {
 22272                    return colliderData;
 273                }
 274            }
 0275            return null;
 276        }
 277
 278        private static void ShowHoverTooltips(this IECSInteractionHoverCanvas canvas,
 279            IReadOnlyList<PBPointerEvents.Types.Entry> entityEvents, bool[] buttonState, float distance, bool isAnyButto
 280        {
 22281            if (entityEvents is null)
 13282                return;
 283
 9284            int tooltipIndex = -1;
 9285            bool shouldAdd = false;
 9286            PBPointerEvents.Types.Entry pointerEvent = null;
 287
 40288            for (int eventIndex = 0; eventIndex < entityEvents.Count; eventIndex++)
 289            {
 11290                shouldAdd = false;
 11291                pointerEvent = entityEvents[eventIndex];
 292
 11293                if (!pointerEvent.EventInfo.GetShowFeedback() || distance > pointerEvent.EventInfo.GetMaxDistance())
 294                    continue;
 295
 9296                int buttonId = (int)pointerEvent.EventInfo.GetButton();
 297
 9298                if (buttonId == (int)InputAction.IaAny)
 299                {
 2300                    if (
 301                        (isAnyButtonDown && pointerEvent.EventType == PointerEventType.PetUp) ||
 302                        (!isAnyButtonDown && pointerEvent.EventType == PointerEventType.PetDown))
 303                    {
 1304                        shouldAdd = true;
 305                    }
 306                }
 7307                else if (buttonId >= 0 && buttonId < buttonState.Length)
 308                {
 7309                    bool buttonIsDown = buttonState[buttonId];
 7310                    if ((pointerEvent.EventType == PointerEventType.PetDown && !buttonIsDown)
 311                        || (pointerEvent.EventType == PointerEventType.PetUp && buttonIsDown))
 312                    {
 4313                        shouldAdd = true;
 314                    }
 315                }
 316
 9317                if (shouldAdd)
 318                {
 5319                    tooltipIndex++;
 5320                    canvas.SetTooltipText(tooltipIndex, pointerEvent.EventInfo.GetHoverText());
 5321                    canvas.SetTooltipInput(tooltipIndex, pointerEvent.EventInfo.GetButton());
 5322                    canvas.SetTooltipActive(tooltipIndex, true);
 323                }
 324            }
 325
 326            // first tooltip free
 44327            for (int i = tooltipIndex + 1; i < canvas.tooltipsCount; i++)
 328            {
 13329                canvas.SetTooltipActive(i, false);
 330            }
 331
 9332            if (tooltipIndex != -1)
 333            {
 5334                canvas.Show();
 335            }
 336            else
 337            {
 4338                canvas.Hide();
 339            }
 4340        }
 341    }
 342}

Methods/Properties

CreateSystem(.IInternalECSComponent[InternalColliders], .IInternalECSComponent[InternalInputEventResults], DCL.ECSRuntime.ECSComponent[PBPointerEvents], IECSInteractionHoverCanvas, DCL.IWorldState, DCL.DataStore_ECS7)
Update(ECSSystems.PointerInputSystem.ECSPointerInputSystem/State)
IsColliderDifferent(ECSSystems.PointerInputSystem.ECSPointerInputSystem/State, DCL.ECSRuntime.IECSReadOnlyComponentData[InternalColliders])
IsColliderMissing(ECSSystems.PointerInputSystem.ECSPointerInputSystem/State, DCL.ECSRuntime.IECSReadOnlyComponentData[InternalColliders])
IsColliderAvailable(ECSSystems.PointerInputSystem.ECSPointerInputSystem/State, DCL.ECSRuntime.IECSReadOnlyComponentData[InternalColliders])
HandleColliderChanged(ECSSystems.PointerInputSystem.ECSPointerInputSystem/State, DCL.ECSRuntime.IECSReadOnlyComponentData[InternalColliders])
HandleMissingCollider(ECSSystems.PointerInputSystem.ECSPointerInputSystem/State)
HandleAvailableCollider(ECSSystems.PointerInputSystem.ECSPointerInputSystem/State, DCL.ECSRuntime.IECSReadOnlyComponentData[InternalColliders])
BroadcastInputResultEvent(ECSSystems.PointerInputSystem.ECSPointerInputSystem/State, DCL.ECSComponents.InputAction, System.Int64, UnityEngine.Ray, DCL.DataStore_ECS7/RaycastEvent/Hit, DCL.ECSComponents.PointerEventType, DCL.Controllers.IParcelScene)
AddInputResultEvent(ECSSystems.PointerInputSystem.ECSPointerInputSystem/State, DCL.ECSComponents.InputAction, DCL.Controllers.IParcelScene, System.Int64, UnityEngine.Ray, DCL.DataStore_ECS7/RaycastEvent/Hit, DCL.ECSComponents.PointerEventType)
GetEntityWithCollider(.IInternalECSComponent[InternalColliders], UnityEngine.Collider)
ShowHoverTooltips(IECSInteractionHoverCanvas, System.Collections.Generic.IReadOnlyList[Entry], System.Boolean[], System.Single, System.Boolean)