< Summary

Class:DCL.MessagingControllersManager
Assembly:DCL.Runtime
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/WorldRuntime/Messaging/MessagingControllersManager.cs
Covered lines:145
Uncovered lines:9
Coverable lines:154
Total lines:363
Line coverage:94.1% (145 of 154)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
MessagingControllersManager(...)0%110100%
Initialize()0%330100%
MarkBusesDirty()0%110100%
PopulateBusesToBeProcessed()0%20200100%
Dispose()0%440100%
ContainsController(...)0%110100%
AddController(...)0%550100%
AddControllerIfNotExists(...)0%220100%
RemoveController(...)0%220100%
DisposeController(...)0%110100%
Enqueue(...)0%110100%
ForceEnqueueToGlobal(...)0%110100%
SetSceneReady(...)0%220100%
HasScenePendingMessages(...)0%4.594066.67%
ProcessMessages()0%12.1712089.47%
ProcessBus(...)0%4.024090%
RefreshControllerEnabledState(...)0%8.36060%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/WorldRuntime/Messaging/MessagingControllersManager.cs

#LineLine coverage
 1using DCL.Controllers;
 2using System.Collections;
 3using System.Collections.Concurrent;
 4using System.Collections.Generic;
 5using MainScripts.DCL.Analytics.PerformanceAnalytics;
 6using UnityEngine;
 7
 8namespace DCL
 9{
 10    public class MessagingControllersManager : IMessagingControllersManager
 11    {
 12        public static bool VERBOSE = false;
 13
 14        private const float MAX_GLOBAL_MSG_BUDGET = 0.02f;
 15        private const float MAX_SYSTEM_MSG_BUDGET_FOR_FAR_SCENES = 0.003f;
 16
 17        private const float GLTF_BUDGET_MAX = 0.033f;
 18        private const float GLTF_BUDGET_MIN = 0.008f;
 19
 20        private const int GLOBAL_MESSAGING_CONTROLLER_SCENE_NUMBER = 999999;
 21
 277522        public ConcurrentDictionary<int, MessagingController> messagingControllers { get; set; } =
 50023            new ConcurrentDictionary<int, MessagingController>();
 24
 25        private Coroutine mainCoroutine;
 26
 3527        public bool hasPendingMessages => pendingMessagesCount > 0;
 28
 50029        public float timeBudgetCounter = MAX_GLOBAL_MSG_BUDGET;
 7430        public long processedInitMessagesCount { get; set; }
 28331        public int pendingMessagesCount { get; set; }
 2708432        public int pendingInitMessagesCount { get; set; }
 33
 034        public bool isRunning => mainCoroutine != null;
 35
 2698436        public bool paused { get; set; }
 37
 50038        private readonly ConcurrentDictionary<int, MessagingController> globalSceneControllers =
 39            new ConcurrentDictionary<int, MessagingController>();
 40
 50041        private readonly List<MessagingController> sortedControllers = new List<MessagingController>();
 50042        private readonly List<MessagingBus> busesToProcess = new List<MessagingBus>();
 43        private int busesToProcessCount = 0;
 44        private int sortedControllersCount = 0;
 45
 46        private MessagingController globalController = null;
 47        private MessagingController currentSceneController = null;
 48
 49        private IMessageProcessHandler messageHandler;
 50
 50051        public MessagingControllersManager(IMessageProcessHandler messageHandler = null)
 52        {
 50053            this.messageHandler = messageHandler;
 50054        }
 55
 56        public void Initialize()
 57        {
 49358            if (messageHandler == null)
 49359                messageHandler = Environment.i.world.sceneController;
 60
 49361            globalController = new MessagingController(this, messageHandler, GLOBAL_MESSAGING_CONTROLLER_SCENE_NUMBER);
 49362            messagingControllers[GLOBAL_MESSAGING_CONTROLLER_SCENE_NUMBER] = globalController;
 63
 49364            Environment.i.world.sceneController.OnSortScenes += MarkBusesDirty;
 65
 49366            if (mainCoroutine == null)
 67            {
 49368                mainCoroutine = CoroutineStarter.Start(ProcessMessages());
 69            }
 49370        }
 71
 50072        bool populateBusesDirty = true;
 73
 74        public void MarkBusesDirty()
 75        {
 55976            populateBusesDirty = true;
 55977        }
 78
 79        public void PopulateBusesToBeProcessed()
 80        {
 105881            lock (sortedControllers)
 105882            lock (busesToProcess)
 83            {
 105884                IWorldState worldState = Environment.i.world.state;
 105885                int currentSceneNumber = worldState.GetCurrentSceneNumber();
 105886                var scenesSortedByDistance = worldState.GetScenesSortedByDistance();
 87
 105888                int count = scenesSortedByDistance.Count; // we need to retrieve list count everytime because it
 89                // may change after a yield return
 90
 105891                sortedControllers.Clear();
 92
 105893                if (currentSceneNumber > 0 && messagingControllers.ContainsKey(currentSceneNumber))
 2394                    currentSceneController = messagingControllers[currentSceneNumber];
 95
 255496                for (int i = 0; i < count; i++)
 97                {
 21998                    int controllerSceneNumber = scenesSortedByDistance[i].sceneData.sceneNumber;
 99
 219100                    if (controllerSceneNumber != currentSceneNumber)
 101                    {
 166102                        if (!messagingControllers.ContainsKey(controllerSceneNumber))
 103                            continue;
 104
 147105                        sortedControllers.Add(messagingControllers[controllerSceneNumber]);
 106                    }
 107                }
 108
 1058109                sortedControllersCount = sortedControllers.Count;
 110
 1058111                bool globalSceneControllerActive = globalSceneControllers.Count > 0;
 1058112                bool globalControllerActive = globalController != null && globalController.enabled;
 1058113                bool currentSceneControllerActive = currentSceneController != null && currentSceneController.enabled;
 114
 1058115                bool atLeastOneControllerShouldBeProcessed = globalSceneControllerActive || globalControllerActive ||
 116                                                             currentSceneControllerActive || sortedControllersCount > 0;
 117
 1058118                if (!atLeastOneControllerShouldBeProcessed)
 1119                    return;
 120
 1057121                busesToProcess.Clear();
 122
 123                //-------------------------------------------------------------------------------------------
 124                // Global scenes
 1057125                using (var globalScenecontrollersIterator = globalSceneControllers.GetEnumerator())
 126                {
 1066127                    while (globalScenecontrollersIterator.MoveNext())
 128                    {
 9129                        busesToProcess.Add(globalScenecontrollersIterator.Current.Value.uiBus);
 9130                        busesToProcess.Add(globalScenecontrollersIterator.Current.Value.initBus);
 9131                        busesToProcess.Add(globalScenecontrollersIterator.Current.Value.systemBus);
 132                    }
 1057133                }
 134
 1057135                if (globalControllerActive)
 136                {
 1051137                    busesToProcess.Add(globalController.initBus);
 138                }
 139
 1057140                if (currentSceneControllerActive)
 141                {
 25142                    busesToProcess.Add(currentSceneController.initBus);
 25143                    busesToProcess.Add(currentSceneController.uiBus);
 25144                    busesToProcess.Add(currentSceneController.systemBus);
 145                }
 146
 2408147                for (int i = 0; i < sortedControllersCount; ++i)
 148                {
 147149                    MessagingController msgController = sortedControllers[i];
 150
 147151                    busesToProcess.Add(msgController.initBus);
 147152                    busesToProcess.Add(msgController.uiBus);
 153                }
 154
 2408155                for (int i = 0; i < sortedControllersCount; ++i)
 156                {
 147157                    MessagingController msgController = sortedControllers[i];
 147158                    busesToProcess.Add(msgController.systemBus);
 159                }
 160
 1057161                busesToProcessCount = busesToProcess.Count;
 1057162            }
 1058163        }
 164
 165        public void Dispose()
 166        {
 493167            if (mainCoroutine != null)
 168            {
 493169                CoroutineStarter.Stop(mainCoroutine);
 493170                mainCoroutine = null;
 171            }
 172
 493173            using (var controllersIterator = messagingControllers.GetEnumerator())
 174            {
 986175                while (controllersIterator.MoveNext())
 176                {
 493177                    controllersIterator.Current.Value.Stop();
 493178                    DisposeController(controllersIterator.Current.Value);
 179                }
 493180            }
 181
 493182            Environment.i.world.sceneController.OnSortScenes -= PopulateBusesToBeProcessed;
 183
 493184            messagingControllers.Clear();
 493185        }
 186
 187        public bool ContainsController(int sceneNumber)
 188        {
 44189            return messagingControllers.ContainsKey(sceneNumber);
 190        }
 191
 192        public void AddController(IMessageProcessHandler messageHandler, int sceneNumber, bool isGlobal = false)
 193        {
 40194            if (!messagingControllers.ContainsKey(sceneNumber))
 195            {
 40196                messagingControllers.TryAdd(sceneNumber, new MessagingController(this, messageHandler, sceneNumber));
 197            }
 198
 40199            if (isGlobal && sceneNumber > 0)
 200            {
 7201                messagingControllers.TryGetValue(sceneNumber, out MessagingController newGlobalSceneController);
 202
 7203                if (!globalSceneControllers.ContainsKey(sceneNumber))
 7204                    globalSceneControllers.TryAdd(sceneNumber, newGlobalSceneController);
 205            }
 206
 40207            PopulateBusesToBeProcessed();
 40208        }
 209
 210        public void AddControllerIfNotExists(IMessageProcessHandler messageHandler, int sceneNumber,
 211            bool isGlobal = false)
 212        {
 42213            if (!ContainsController(sceneNumber))
 40214                AddController(messageHandler, sceneNumber, isGlobal);
 42215        }
 216
 217        public void RemoveController(int sceneNumber)
 218        {
 285219            if (messagingControllers.ContainsKey(sceneNumber))
 220            {
 221                // In case there is any pending message from a scene being unloaded we decrease the count accordingly
 40222                pendingMessagesCount -= messagingControllers[sceneNumber].messagingBuses[MessagingBusType.INIT]
 223                                                                         .pendingMessagesCount +
 224                                        messagingControllers[sceneNumber].messagingBuses[MessagingBusType.UI]
 225                                                                         .pendingMessagesCount +
 226                                        messagingControllers[sceneNumber].messagingBuses[MessagingBusType.SYSTEM]
 227                                                                         .pendingMessagesCount;
 228
 40229                DisposeController(messagingControllers[sceneNumber]);
 40230                messagingControllers.TryRemove(sceneNumber, out MessagingController _);
 231            }
 232
 285233            globalSceneControllers.TryRemove(sceneNumber, out MessagingController _);
 285234        }
 235
 236        void DisposeController(MessagingController controller)
 237        {
 533238            controller.Stop();
 533239            controller.Dispose();
 533240        }
 241
 242        public void Enqueue(bool isUiBus, QueuedSceneMessage_Scene queuedMessage)
 243        {
 2244            PerformanceAnalytics.MessagesEnqueuedTracker.Track();
 2245            messagingControllers[queuedMessage.sceneNumber].Enqueue(isUiBus, queuedMessage, out MessagingBusType busId);
 2246        }
 247
 248        public void ForceEnqueueToGlobal(MessagingBusType busId, QueuedSceneMessage queuedMessage)
 249        {
 33250            PerformanceAnalytics.MessagesEnqueuedTracker.Track();
 33251            messagingControllers[GLOBAL_MESSAGING_CONTROLLER_SCENE_NUMBER].ForceEnqueue(busId, queuedMessage);
 33252        }
 253
 254        public void SetSceneReady(int sceneNumber)
 255        {
 256            // Start processing SYSTEM queue
 244257            if (messagingControllers.ContainsKey(sceneNumber))
 258            {
 259                // Start processing SYSTEM queue
 2260                MessagingController sceneMessagingController = messagingControllers[sceneNumber];
 2261                sceneMessagingController.StartBus(MessagingBusType.SYSTEM);
 2262                sceneMessagingController.StartBus(MessagingBusType.UI);
 2263                sceneMessagingController.StopBus(MessagingBusType.INIT);
 264            }
 244265        }
 266
 267        public bool HasScenePendingMessages(int sceneNumber)
 268        {
 7269            if (!messagingControllers.TryGetValue(sceneNumber, out MessagingController newGlobalSceneController))
 0270                return false;
 271
 7272            return newGlobalSceneController.initBus.hasPendingMessages
 273                   || newGlobalSceneController.systemBus.hasPendingMessages
 274                   || newGlobalSceneController.uiBus.hasPendingMessages;
 275        }
 276
 277        IEnumerator ProcessMessages()
 278        {
 26447279            while (true)
 280            {
 26940281                if (paused)
 282                {
 0283                    yield return null;
 284
 0285                    continue;
 286                }
 287
 26940288                if (populateBusesDirty)
 289                {
 1018290                    PopulateBusesToBeProcessed();
 1018291                    populateBusesDirty = false;
 292                }
 293
 26940294                timeBudgetCounter =
 295                    CommonScriptableObjects.rendererState.Get() ? MAX_GLOBAL_MSG_BUDGET : float.MaxValue;
 296
 108380297                for (int i = 0; i < busesToProcessCount; ++i)
 298                {
 299                    MessagingBus bus;
 300
 27250301                    lock (busesToProcess)
 302                    {
 27250303                        bus = busesToProcess[i];
 27250304                    }
 305
 27250306                    if (ProcessBus(bus))
 307                        break;
 308                }
 309
 26940310                if (pendingInitMessagesCount == 0)
 311                {
 26928312                    AssetPromiseKeeper_GLTF.i.throttlingCounter.budgetPerFrameInMilliseconds =
 313                        Mathf.Clamp(timeBudgetCounter, GLTF_BUDGET_MIN, GLTF_BUDGET_MAX) * 1000f;
 314                }
 315                else
 316                {
 12317                    AssetPromiseKeeper_GLTF.i.throttlingCounter.budgetPerFrameInMilliseconds = 0;
 318                }
 319
 26940320                yield return null;
 321            }
 322        }
 323
 324        bool ProcessBus(MessagingBus bus)
 325        {
 27250326            if (!bus.enabled || bus.pendingMessagesCount <= 0)
 27235327                return false;
 328
 15329            float startTime = Time.realtimeSinceStartup;
 330
 15331            float timeBudget = timeBudgetCounter;
 332
 333            //TODO(Brian): We should use the returning yieldReturn IEnumerator and MoveNext() it manually each frame to
 334            //             account the coroutine processing into the budget. Until we do that we just skip it.
 15335            bus.ProcessQueue(timeBudget, out _);
 15336            RefreshControllerEnabledState(bus.owner);
 337
 15338            timeBudgetCounter -= Time.realtimeSinceStartup - startTime;
 339
 15340            if (timeBudgetCounter <= 0)
 0341                return true;
 342
 15343            return false;
 344        }
 345
 346        private void RefreshControllerEnabledState(MessagingController controller)
 347        {
 15348            if (controller == null || !controller.enabled)
 0349                return;
 350
 15351            if (controller.uiBus.pendingMessagesCount != 0)
 0352                return;
 353
 15354            if (controller.initBus.pendingMessagesCount != 0)
 0355                return;
 356
 15357            if (controller.systemBus.pendingMessagesCount != 0)
 0358                return;
 359
 15360            controller.enabled = false;
 15361        }
 362    }
 363}