< 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:135
Uncovered lines:21
Coverable lines:156
Total lines:366
Line coverage:86.5% (135 of 156)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
MessagingControllersManager(...)0%110100%
Initialize()0%440100%
MarkBusesDirty()0%110100%
PopulateBusesToBeProcessed()0%2020098%
Dispose()0%440100%
ContainsController(...)0%110100%
AddController(...)0%550100%
AddControllerIfNotExists(...)0%220100%
RemoveController(...)0%220100%
DisposeController(...)0%110100%
Enqueue(...)0%2100%
ForceEnqueueToGlobal(...)0%110100%
SetSceneReady(...)0%3.192033.33%
HasScenePendingMessages(...)0%20400%
ProcessMessages()0%12.4912085%
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        public const string GLOBAL_MESSAGING_CONTROLLER = "global_messaging_controller";
 21
 022        public ConcurrentDictionary<string, MessagingController> messagingControllers { get; set; } =
 67423            new ConcurrentDictionary<string, MessagingController>();
 24
 25        private Coroutine mainCoroutine;
 26
 3327        public bool hasPendingMessages => pendingMessagesCount > 0;
 28
 67429        public float timeBudgetCounter = MAX_GLOBAL_MSG_BUDGET;
 6030        public long processedInitMessagesCount { get; set; }
 14831        public int pendingMessagesCount { get; set; }
 12032        public int pendingInitMessagesCount { get; set; }
 33
 034        public bool isRunning => mainCoroutine != null;
 35
 4436        public bool paused { get; set; }
 37
 67438        private readonly ConcurrentDictionary<string, MessagingController> globalSceneControllers =
 39            new ConcurrentDictionary<string, MessagingController>();
 40
 67441        private readonly List<MessagingController> sortedControllers = new List<MessagingController>();
 67442        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
 67451        public MessagingControllersManager(IMessageProcessHandler messageHandler = null)
 52        {
 67453            this.messageHandler = messageHandler;
 67454        }
 55
 56        public void Initialize()
 57        {
 66758            if (messageHandler == null)
 66759                messageHandler = Environment.i.world.sceneController;
 60
 66761            messagingControllers[GLOBAL_MESSAGING_CONTROLLER] =
 62                new MessagingController(this, messageHandler, GLOBAL_MESSAGING_CONTROLLER);
 63
 66764            if (!string.IsNullOrEmpty(GLOBAL_MESSAGING_CONTROLLER))
 66765                messagingControllers.TryGetValue(GLOBAL_MESSAGING_CONTROLLER, out globalController);
 66
 66767            Environment.i.world.sceneController.OnSortScenes += MarkBusesDirty;
 68
 66769            if (mainCoroutine == null)
 70            {
 66771                mainCoroutine = CoroutineStarter.Start(ProcessMessages());
 72            }
 66773        }
 74
 67475        bool populateBusesDirty = true;
 76
 77        public void MarkBusesDirty()
 78        {
 72779            populateBusesDirty = true;
 72780        }
 81
 82        public void PopulateBusesToBeProcessed()
 83        {
 139584            lock (sortedControllers)
 139585            lock (busesToProcess)
 86            {
 139587                IWorldState worldState = Environment.i.world.state;
 139588                string currentSceneId = worldState.GetCurrentSceneId();
 139589                var scenesSortedByDistance = worldState.GetScenesSortedByDistance();
 90
 139591                int count = scenesSortedByDistance.Count; // we need to retrieve list count everytime because it
 92                // may change after a yield return
 93
 139594                sortedControllers.Clear();
 95
 139596                if (!string.IsNullOrEmpty(currentSceneId) && messagingControllers.ContainsKey(currentSceneId))
 1197                    currentSceneController = messagingControllers[currentSceneId];
 98
 321099                for (int i = 0; i < count; i++)
 100                {
 210101                    string controllerId = scenesSortedByDistance[i].sceneData.id;
 102
 210103                    if (controllerId != currentSceneId)
 104                    {
 151105                        if (!messagingControllers.ContainsKey(controllerId))
 106                            continue;
 107
 148108                        sortedControllers.Add(messagingControllers[controllerId]);
 109                    }
 110                }
 111
 1395112                sortedControllersCount = sortedControllers.Count;
 113
 1395114                bool globalSceneControllerActive = globalSceneControllers.Count > 0;
 1395115                bool globalControllerActive = globalController != null && globalController.enabled;
 1395116                bool currentSceneControllerActive = currentSceneController != null && currentSceneController.enabled;
 117
 1395118                bool atLeastOneControllerShouldBeProcessed = globalSceneControllerActive || globalControllerActive ||
 119                                                             currentSceneControllerActive || sortedControllersCount > 0;
 120
 1395121                if (!atLeastOneControllerShouldBeProcessed)
 0122                    return;
 123
 1395124                busesToProcess.Clear();
 125
 126                //-------------------------------------------------------------------------------------------
 127                // Global scenes
 1395128                using (var globalScenecontrollersIterator = globalSceneControllers.GetEnumerator())
 129                {
 1401130                    while (globalScenecontrollersIterator.MoveNext())
 131                    {
 6132                        busesToProcess.Add(globalScenecontrollersIterator.Current.Value.uiBus);
 6133                        busesToProcess.Add(globalScenecontrollersIterator.Current.Value.initBus);
 6134                        busesToProcess.Add(globalScenecontrollersIterator.Current.Value.systemBus);
 135                    }
 1395136                }
 137
 1395138                if (globalControllerActive)
 139                {
 1390140                    busesToProcess.Add(globalController.initBus);
 141                }
 142
 1395143                if (currentSceneControllerActive)
 144                {
 12145                    busesToProcess.Add(currentSceneController.initBus);
 12146                    busesToProcess.Add(currentSceneController.uiBus);
 12147                    busesToProcess.Add(currentSceneController.systemBus);
 148                }
 149
 3086150                for (int i = 0; i < sortedControllersCount; ++i)
 151                {
 148152                    MessagingController msgController = sortedControllers[i];
 153
 148154                    busesToProcess.Add(msgController.initBus);
 148155                    busesToProcess.Add(msgController.uiBus);
 156                }
 157
 3086158                for (int i = 0; i < sortedControllersCount; ++i)
 159                {
 148160                    MessagingController msgController = sortedControllers[i];
 148161                    busesToProcess.Add(msgController.systemBus);
 162                }
 163
 1395164                busesToProcessCount = busesToProcess.Count;
 1395165            }
 1395166        }
 167
 168        public void Dispose()
 169        {
 667170            if (mainCoroutine != null)
 171            {
 667172                CoroutineStarter.Stop(mainCoroutine);
 667173                mainCoroutine = null;
 174            }
 175
 667176            using (var controllersIterator = messagingControllers.GetEnumerator())
 177            {
 1334178                while (controllersIterator.MoveNext())
 179                {
 667180                    controllersIterator.Current.Value.Stop();
 667181                    DisposeController(controllersIterator.Current.Value);
 182                }
 667183            }
 184
 667185            Environment.i.world.sceneController.OnSortScenes -= PopulateBusesToBeProcessed;
 186
 667187            messagingControllers.Clear();
 667188        }
 189
 190        public bool ContainsController(string sceneId)
 191        {
 33192            return messagingControllers.ContainsKey(sceneId);
 193        }
 194
 195        public void AddController(IMessageProcessHandler messageHandler, string sceneId, bool isGlobal = false)
 196        {
 33197            if (!messagingControllers.ContainsKey(sceneId))
 198            {
 33199                messagingControllers.TryAdd(sceneId, new MessagingController(this, messageHandler, sceneId));
 200            }
 201
 33202            if (isGlobal && !string.IsNullOrEmpty(sceneId))
 203            {
 5204                messagingControllers.TryGetValue(sceneId, out MessagingController newGlobalSceneController);
 205
 5206                if (!globalSceneControllers.ContainsKey(sceneId))
 5207                    globalSceneControllers.TryAdd(sceneId, newGlobalSceneController);
 208            }
 209
 33210            PopulateBusesToBeProcessed();
 33211        }
 212
 213        public void AddControllerIfNotExists(IMessageProcessHandler messageHandler, string sceneId,
 214            bool isGlobal = false)
 215        {
 33216            if (!ContainsController(sceneId))
 33217                AddController(messageHandler, sceneId, isGlobal);
 33218        }
 219
 220        public void RemoveController(string sceneId)
 221        {
 426222            if (messagingControllers.ContainsKey(sceneId))
 223            {
 224                // In case there is any pending message from a scene being unloaded we decrease the count accordingly
 33225                pendingMessagesCount -= messagingControllers[sceneId].messagingBuses[MessagingBusType.INIT]
 226                                            .pendingMessagesCount +
 227                                        messagingControllers[sceneId].messagingBuses[MessagingBusType.UI]
 228                                            .pendingMessagesCount +
 229                                        messagingControllers[sceneId].messagingBuses[MessagingBusType.SYSTEM]
 230                                            .pendingMessagesCount;
 231
 33232                DisposeController(messagingControllers[sceneId]);
 33233                messagingControllers.TryRemove(sceneId, out MessagingController _);
 234            }
 235
 426236            globalSceneControllers.TryRemove(sceneId, out MessagingController _);
 426237        }
 238
 239        void DisposeController(MessagingController controller)
 240        {
 700241            controller.Stop();
 700242            controller.Dispose();
 700243        }
 244
 245        public void Enqueue(bool isUiBus, QueuedSceneMessage_Scene queuedMessage)
 246        {
 0247            PerformanceAnalytics.MessagesEnqueuedTracker.Track();
 0248            messagingControllers[queuedMessage.sceneId].Enqueue(isUiBus, queuedMessage, out MessagingBusType busId);
 0249        }
 250
 251        public void ForceEnqueueToGlobal(MessagingBusType busId, QueuedSceneMessage queuedMessage)
 252        {
 30253            PerformanceAnalytics.MessagesEnqueuedTracker.Track();
 30254            messagingControllers[GLOBAL_MESSAGING_CONTROLLER].ForceEnqueue(busId, queuedMessage);
 30255        }
 256
 257        public void SetSceneReady(string sceneId)
 258        {
 259            // Start processing SYSTEM queue
 394260            if (messagingControllers.ContainsKey(sceneId))
 261            {
 262                // Start processing SYSTEM queue
 0263                MessagingController sceneMessagingController = messagingControllers[sceneId];
 0264                sceneMessagingController.StartBus(MessagingBusType.SYSTEM);
 0265                sceneMessagingController.StartBus(MessagingBusType.UI);
 0266                sceneMessagingController.StopBus(MessagingBusType.INIT);
 267            }
 394268        }
 269
 270        public bool HasScenePendingMessages(string sceneId)
 271        {
 0272            if (!messagingControllers.TryGetValue(sceneId, out MessagingController newGlobalSceneController))
 0273                return false;
 274
 0275            return newGlobalSceneController.initBus.hasPendingMessages
 276                   || newGlobalSceneController.systemBus.hasPendingMessages
 277                   || newGlobalSceneController.uiBus.hasPendingMessages;
 278        }
 279
 280        IEnumerator ProcessMessages()
 281        {
 7041282            while (true)
 283            {
 7708284                if (paused)
 285                {
 0286                    yield return null;
 287
 0288                    continue;
 289                }
 290
 7708291                if (populateBusesDirty)
 292                {
 1362293                    PopulateBusesToBeProcessed();
 1362294                    populateBusesDirty = false;
 295                }
 296
 7708297                timeBudgetCounter =
 298                    CommonScriptableObjects.rendererState.Get() ? MAX_GLOBAL_MSG_BUDGET : float.MaxValue;
 299
 31280300                for (int i = 0; i < busesToProcessCount; ++i)
 301                {
 302                    MessagingBus bus;
 303
 7932304                    lock (busesToProcess)
 305                    {
 7932306                        bus = busesToProcess[i];
 7932307                    }
 308
 7932309                    if (ProcessBus(bus))
 310                        break;
 311                }
 312
 7708313                if (pendingInitMessagesCount == 0)
 314                {
 7708315                    AssetPromiseKeeper_GLTF.i.throttlingCounter.budgetPerFrameInMilliseconds =
 316                        Mathf.Clamp(timeBudgetCounter, GLTF_BUDGET_MIN, GLTF_BUDGET_MAX) * 1000f;
 7708317                }
 318                else
 319                {
 0320                    AssetPromiseKeeper_GLTF.i.throttlingCounter.budgetPerFrameInMilliseconds = 0;
 321                }
 322
 7708323                yield return null;
 324            }
 325        }
 326
 327        bool ProcessBus(MessagingBus bus)
 328        {
 7932329            if (!bus.enabled || bus.pendingMessagesCount <= 0)
 7922330                return false;
 331
 10332            float startTime = Time.realtimeSinceStartup;
 333
 10334            float timeBudget = timeBudgetCounter;
 335
 336            //TODO(Brian): We should use the returning yieldReturn IEnumerator and MoveNext() it manually each frame to
 337            //             account the coroutine processing into the budget. Until we do that we just skip it.
 10338            bus.ProcessQueue(timeBudget, out _);
 10339            RefreshControllerEnabledState(bus.owner);
 340
 10341            timeBudgetCounter -= Time.realtimeSinceStartup - startTime;
 342
 10343            if (timeBudgetCounter <= 0)
 0344                return true;
 345
 10346            return false;
 347        }
 348
 349        private void RefreshControllerEnabledState(MessagingController controller)
 350        {
 10351            if (controller == null || !controller.enabled)
 0352                return;
 353
 10354            if (controller.uiBus.pendingMessagesCount != 0)
 0355                return;
 356
 10357            if (controller.initBus.pendingMessagesCount != 0)
 0358                return;
 359
 10360            if (controller.systemBus.pendingMessagesCount != 0)
 0361                return;
 362
 10363            controller.enabled = false;
 10364        }
 365    }
 366}