< Summary

Class:DCL.SceneController
Assembly:DCL.Runtime
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/WorldRuntime/SceneController.cs
Covered lines:187
Uncovered lines:155
Coverable lines:342
Total lines:873
Line coverage:54.6% (187 of 342)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
SceneController()0%110100%
Initialize()0%22093.33%
SetupDeferredRunners()0%110100%
PrewarmSceneMessagesPool()0%20400%
OnDebugModeSet(...)0%4.123050%
Dispose()0%220100%
Update()0%440100%
LateUpdate()0%220100%
ProcessMessage(...)0%10.3410085%
ProcessMessage(...)0%1356.2847016%
ParseQuery(...)0%12300%
SendSceneMessage(...)0%6200%
Decode(...)0%20400%
DeferredDecodingAndEnqueue()0%7.777075%
EnqueueChunk(...)0%12300%
WatchForNewChunksToDecode()0%30500%
ThreadedDecodeAndEnqueue(...)0%20400%
EnqueueSceneMessage(...)0%110100%
SendSceneReady(...)0%2.022083.33%
SetPositionDirty(...)0%4.054085.71%
SortScenesByDistance()0%440100%
OnCurrentSceneNumberChange(...)0%440100%
LoadParcelScenesExecute(...)0%330100%
LoadUnityParcelScene(...)0%14.2512075%
UpdateParcelScenesExecute(...)0%20400%
UpdateParcelScenesExecute(...)0%42600%
UnloadScene(...)0%220100%
UnloadParcelSceneExecute(...)0%6.116085.71%
UnloadAllScenes(...)0%440100%
LoadParcelScenes(...)0%3.043083.33%
UpdateParcelScenes(...)0%6200%
UnloadAllScenesQueued()0%6200%
CreateGlobalScene(...)0%10.9810078.57%
IsolateScene(...)0%12300%
ReIntegrateIsolatedScene()0%6200%

File(s)

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

#LineLine coverage
 1using DCL.Controllers;
 2using DCL.Helpers;
 3using DCL.Interface;
 4using DCL.Models;
 5using DCL.Configuration;
 6using System;
 7using System.Collections;
 8using System.Collections.Concurrent;
 9using System.ComponentModel;
 10using System.Linq;
 11using System.Threading;
 12using Cysharp.Threading.Tasks;
 13using DCL.Components;
 14using DCL.CRDT;
 15using UnityEngine;
 16using Debug = UnityEngine.Debug;
 17
 18namespace DCL
 19{
 20    public class SceneController : ISceneController
 21    {
 22        public static bool VERBOSE = false;
 23        const int SCENE_MESSAGES_PREWARM_COUNT = 100000;
 24
 5394225        public bool enabled { get; set; } = true;
 226        internal BaseVariable<Transform> isPexViewerInitialized => DataStore.i.experiencesViewer.isInitialized;
 27
 28        //TODO(Brian): Move to WorldRuntimePlugin later
 29        private LoadingFeedbackController loadingFeedbackController;
 30        private Coroutine deferredDecodingCoroutine;
 31
 32        private CancellationTokenSource tokenSource;
 62433        private IMessagingControllersManager messagingControllersManager => Environment.i.messaging.manager;
 34
 51235        public EntityIdHelper entityIdHelper { get; } = new EntityIdHelper();
 36
 37        public void Initialize()
 38        {
 51239            tokenSource = new CancellationTokenSource();
 51240            sceneSortDirty = true;
 51241            positionDirty = true;
 51242            lastSortFrame = 0;
 51243            enabled = true;
 44
 51245            loadingFeedbackController = new LoadingFeedbackController();
 46
 51247            DataStore.i.debugConfig.isDebugMode.OnChange += OnDebugModeSet;
 48
 51249            SetupDeferredRunners();
 50
 51251            DataStore.i.player.playerGridPosition.OnChange += SetPositionDirty;
 51252            CommonScriptableObjects.sceneNumber.OnChange += OnCurrentSceneNumberChange;
 53
 54            // TODO(Brian): Move this later to Main.cs
 51255            if ( !EnvironmentSettings.RUNNING_TESTS )
 56            {
 057                PrewarmSceneMessagesPool();
 58            }
 59
 51260            Environment.i.platform.updateEventHandler.AddListener(IUpdateEventHandler.EventType.Update, Update);
 51261            Environment.i.platform.updateEventHandler.AddListener(IUpdateEventHandler.EventType.LateUpdate, LateUpdate);
 51262        }
 63        private void SetupDeferredRunners()
 64        {
 65#if UNITY_WEBGL
 51266            deferredDecodingCoroutine = CoroutineStarter.Start(DeferredDecodingAndEnqueue());
 67#else
 68            CancellationToken tokenSourceToken = tokenSource.Token;
 69            TaskUtils.Run(async () => await WatchForNewChunksToDecode(tokenSourceToken), cancellationToken: tokenSourceT
 70#endif
 51271        }
 72
 73        private void PrewarmSceneMessagesPool()
 74        {
 075            if (prewarmSceneMessagesPool)
 76            {
 077                for (int i = 0; i < SCENE_MESSAGES_PREWARM_COUNT; i++)
 78                {
 079                    sceneMessagesPool.Enqueue(new QueuedSceneMessage_Scene());
 80                }
 81            }
 82
 083            if (prewarmEntitiesPool)
 84            {
 085                PoolManagerFactory.EnsureEntityPool(prewarmEntitiesPool);
 86            }
 087        }
 88
 89        private void OnDebugModeSet(bool current, bool previous)
 90        {
 3091            if (current == previous)
 092                return;
 93
 3094            if (current)
 95            {
 3096                Environment.i.world.sceneBoundsChecker.SetFeedbackStyle(new SceneBoundsFeedbackStyle_RedBox());
 97            }
 98            else
 99            {
 0100                Environment.i.world.sceneBoundsChecker.SetFeedbackStyle(new SceneBoundsFeedbackStyle_Simple());
 101            }
 0102        }
 103
 104        public void Dispose()
 105        {
 512106            tokenSource.Cancel();
 512107            tokenSource.Dispose();
 512108            loadingFeedbackController.Dispose();
 109
 512110            Environment.i.platform.updateEventHandler.RemoveListener(IUpdateEventHandler.EventType.Update, Update);
 512111            Environment.i.platform.updateEventHandler.RemoveListener(IUpdateEventHandler.EventType.LateUpdate, LateUpdat
 112
 512113            PoolManager.i.OnGet -= Environment.i.platform.physicsSyncController.MarkDirty;
 512114            PoolManager.i.OnGet -= Environment.i.platform.cullingController.objectsTracker.MarkDirty;
 115
 512116            DataStore.i.player.playerGridPosition.OnChange -= SetPositionDirty;
 512117            DataStore.i.debugConfig.isDebugMode.OnChange -= OnDebugModeSet;
 118
 512119            CommonScriptableObjects.sceneNumber.OnChange -= OnCurrentSceneNumberChange;
 120
 512121            UnloadAllScenes(includePersistent: true);
 122
 512123            if (deferredDecodingCoroutine != null)
 512124                CoroutineStarter.Stop(deferredDecodingCoroutine);
 512125        }
 126
 127        public void Update()
 128        {
 26447129            if (!enabled)
 74130                return;
 131
 26373132            if (lastSortFrame != Time.frameCount && sceneSortDirty)
 133            {
 515134                lastSortFrame = Time.frameCount;
 515135                sceneSortDirty = false;
 515136                SortScenesByDistance();
 137            }
 26373138        }
 139
 140        public void LateUpdate()
 141        {
 26447142            if (!enabled)
 74143                return;
 144
 26373145            Environment.i.platform.physicsSyncController.Sync();
 26373146        }
 147
 148        //======================================================================
 149
 150        #region MESSAGES_HANDLING
 151
 152        //======================================================================
 153
 154#if UNITY_EDITOR
 155        public delegate void ProcessDelegate(int sceneNumber, string method);
 156
 157        public event ProcessDelegate OnMessageProcessInfoStart;
 158        public event ProcessDelegate OnMessageProcessInfoEnds;
 159#endif
 0160        public bool deferredMessagesDecoding { get; set; } = false;
 161
 512162        readonly ConcurrentQueue<string> chunksToDecode = new ConcurrentQueue<string>();
 512163        private readonly ConcurrentQueue<QueuedSceneMessage_Scene> messagesToProcess = new ConcurrentQueue<QueuedSceneMe
 164
 165        const float MAX_TIME_FOR_DECODE = 0.005f;
 166
 167        public bool ProcessMessage(QueuedSceneMessage_Scene msgObject, out CustomYieldInstruction yieldInstruction)
 168        {
 2169            int sceneNumber = msgObject.sceneNumber;
 2170            string method = msgObject.method;
 171
 2172            yieldInstruction = null;
 173
 174            IParcelScene scene;
 2175            bool res = false;
 2176            IWorldState worldState = Environment.i.world.state;
 2177            DebugConfig debugConfig = DataStore.i.debugConfig;
 178
 2179            if (worldState.TryGetScene(sceneNumber, out scene))
 180            {
 181#if UNITY_EDITOR
 2182                if (debugConfig.soloScene && scene is GlobalScene && debugConfig.ignoreGlobalScenes)
 183                {
 0184                    return false;
 185                }
 186#endif
 2187                if (!scene.GetSceneTransform().gameObject.activeInHierarchy)
 188                {
 0189                    return true;
 190                }
 191
 192#if UNITY_EDITOR
 2193                OnMessageProcessInfoStart?.Invoke(sceneNumber, method);
 194#endif
 2195                ProfilingEvents.OnMessageProcessStart?.Invoke(method);
 196
 2197                ProcessMessage(scene as ParcelScene, method, msgObject.payload, out yieldInstruction);
 198
 2199                ProfilingEvents.OnMessageProcessEnds?.Invoke(method);
 200
 201#if UNITY_EDITOR
 2202                OnMessageProcessInfoEnds?.Invoke(sceneNumber, method);
 203#endif
 204
 2205                res = true;
 206            }
 207
 208            else
 209            {
 0210                res = false;
 211            }
 212
 2213            sceneMessagesPool.Enqueue(msgObject);
 214
 2215            return res;
 216        }
 217
 218        private void ProcessMessage(ParcelScene scene, string method, object msgPayload,
 219            out CustomYieldInstruction yieldInstruction)
 220        {
 2221            yieldInstruction = null;
 2222            IDelayedComponent delayedComponent = null;
 223
 224            try
 225            {
 226                switch (method)
 227                {
 228                    case MessagingTypes.ENTITY_CREATE:
 229                        {
 0230                            if (msgPayload is Protocol.CreateEntity payload)
 0231                                scene.CreateEntity(entityIdHelper.EntityFromLegacyEntityString(payload.entityId));
 232
 0233                            break;
 234                        }
 235                    case MessagingTypes.ENTITY_REPARENT:
 236                        {
 0237                            if (msgPayload is Protocol.SetEntityParent payload)
 0238                                scene.SetEntityParent(entityIdHelper.EntityFromLegacyEntityString(payload.entityId),
 239                                    entityIdHelper.EntityFromLegacyEntityString(payload.parentId));
 240
 0241                            break;
 242                        }
 243
 244                    case MessagingTypes.ENTITY_COMPONENT_CREATE_OR_UPDATE:
 245                        {
 0246                            if (msgPayload is Protocol.EntityComponentCreateOrUpdate payload)
 247                            {
 0248                                delayedComponent = scene.componentsManagerLegacy.EntityComponentCreateOrUpdate(
 249                                    entityIdHelper.EntityFromLegacyEntityString(payload.entityId),
 250                                    (CLASS_ID_COMPONENT) payload.classId, payload.json) as IDelayedComponent;
 251                            }
 252
 0253                            break;
 254                        }
 255
 256                    case MessagingTypes.ENTITY_COMPONENT_DESTROY:
 257                        {
 0258                            if (msgPayload is Protocol.EntityComponentDestroy payload)
 0259                                scene.componentsManagerLegacy.EntityComponentRemove(
 260                                    entityIdHelper.EntityFromLegacyEntityString(payload.entityId), payload.name);
 261
 0262                            break;
 263                        }
 264
 265                    case MessagingTypes.SHARED_COMPONENT_ATTACH:
 266                        {
 0267                            if (msgPayload is Protocol.SharedComponentAttach payload)
 0268                                scene.componentsManagerLegacy.SceneSharedComponentAttach(
 269                                    entityIdHelper.EntityFromLegacyEntityString(payload.entityId), payload.id);
 270
 0271                            break;
 272                        }
 273
 274                    case MessagingTypes.SHARED_COMPONENT_CREATE:
 275                        {
 0276                            if (msgPayload is Protocol.SharedComponentCreate payload)
 0277                                scene.componentsManagerLegacy.SceneSharedComponentCreate(payload.id, payload.classId);
 278
 0279                            break;
 280                        }
 281
 282                    case MessagingTypes.SHARED_COMPONENT_DISPOSE:
 283                        {
 0284                            if (msgPayload is Protocol.SharedComponentDispose payload)
 0285                                scene.componentsManagerLegacy.SceneSharedComponentDispose(payload.id);
 286
 0287                            break;
 288                        }
 289
 290                    case MessagingTypes.SHARED_COMPONENT_UPDATE:
 291                        {
 0292                            if (msgPayload is Protocol.SharedComponentUpdate payload)
 0293                                delayedComponent = scene.componentsManagerLegacy.SceneSharedComponentUpdate(payload.comp
 294
 0295                            break;
 296                        }
 297
 298                    case MessagingTypes.ENTITY_DESTROY:
 299                        {
 0300                            if (msgPayload is Protocol.RemoveEntity payload)
 0301                                scene.RemoveEntity(entityIdHelper.EntityFromLegacyEntityString(payload.entityId));
 302
 0303                            break;
 304                        }
 305
 306                    case MessagingTypes.INIT_DONE:
 307                        {
 2308                            if (!scene.IsInitMessageDone())
 309                            {
 2310                                scene.sceneLifecycleHandler.SetInitMessagesDone();
 311                            }
 2312                            break;
 313                        }
 314
 315                    case MessagingTypes.QUERY:
 316                        {
 0317                            if (msgPayload is QueryMessage queryMessage)
 0318                                ParseQuery(queryMessage.payload, scene.sceneData.sceneNumber);
 319
 0320                            break;
 321                        }
 322
 323                    case MessagingTypes.OPEN_EXTERNAL_URL:
 324                        {
 0325                            if (msgPayload is Protocol.OpenExternalUrl payload)
 0326                                OnOpenExternalUrlRequest?.Invoke(scene, payload.url);
 327
 0328                            break;
 329                        }
 330
 331                    case MessagingTypes.OPEN_NFT_DIALOG:
 332                        {
 0333                            if (msgPayload is Protocol.OpenNftDialog payload)
 0334                                DataStore.i.common.onOpenNFTPrompt.Set(new NFTPromptModel(payload.contactAddress, payloa
 335                                    payload.comment), true);
 336
 0337                            break;
 338                        }
 339
 340                    default:
 0341                        Debug.LogError($"Unknown method {method}");
 342
 343                        break;
 344                }
 2345            }
 346            catch (Exception e)
 347            {
 0348                Debug.LogException(e);
 0349                Debug.LogError($"Scene message error. scene: {scene.sceneData.sceneNumber} method: {method} payload: {Js
 0350            }
 351
 2352            if (delayedComponent != null)
 353            {
 0354                if (delayedComponent.isRoutineRunning)
 0355                    yieldInstruction = delayedComponent.yieldInstruction;
 356            }
 2357        }
 358
 359        public void ParseQuery(object payload, int sceneNumber)
 360        {
 0361            if (!Environment.i.world.state.TryGetScene(sceneNumber, out var scene)) return;
 362
 0363            if (!(payload is RaycastQuery raycastQuery))
 0364                return;
 365
 0366            Vector3 worldOrigin = raycastQuery.ray.origin + Utils.GridToWorldPosition(scene.sceneData.basePosition.x, sc
 367
 0368            raycastQuery.ray.unityOrigin = PositionUtils.WorldToUnityPosition(worldOrigin);
 0369            raycastQuery.sceneNumber = sceneNumber;
 0370            PhysicsCast.i.Query(raycastQuery, entityIdHelper);
 0371        }
 372
 373        public void SendSceneMessage(string chunk)
 374        {
 0375            var renderer = CommonScriptableObjects.rendererState.Get();
 376
 0377            if (!renderer)
 378            {
 0379                EnqueueChunk(chunk);
 380            }
 381            else
 382            {
 0383                chunksToDecode.Enqueue(chunk);
 384            }
 0385        }
 386
 387        private QueuedSceneMessage_Scene Decode(string payload, QueuedSceneMessage_Scene queuedMessage)
 388        {
 0389            ProfilingEvents.OnMessageDecodeStart?.Invoke("Misc");
 390
 0391            if (!MessageDecoder.DecodePayloadChunk(payload,
 392                    out int sceneNumber,
 393                    out string message,
 394                    out string messageTag,
 395                    out PB_SendSceneMessage sendSceneMessage))
 396            {
 0397                return null;
 398            }
 399
 0400            MessageDecoder.DecodeSceneMessage(sceneNumber, message, messageTag, sendSceneMessage, ref queuedMessage);
 401
 0402            ProfilingEvents.OnMessageDecodeEnds?.Invoke("Misc");
 403
 0404            return queuedMessage;
 405        }
 406
 407        private IEnumerator DeferredDecodingAndEnqueue()
 408        {
 512409            float start = Time.realtimeSinceStartup;
 410            float maxTimeForDecode;
 411
 26716412            while (true)
 413            {
 27228414                maxTimeForDecode = CommonScriptableObjects.rendererState.Get() ? MAX_TIME_FOR_DECODE : float.MaxValue;
 415
 27228416                if (chunksToDecode.TryDequeue(out string chunk))
 417                {
 0418                    EnqueueChunk(chunk);
 419
 0420                    if (Time.realtimeSinceStartup - start < maxTimeForDecode)
 421                        continue;
 422                }
 423
 27228424                yield return null;
 425
 26716426                start = Time.unscaledTime;
 427            }
 428        }
 429        private void EnqueueChunk(string chunk)
 430        {
 0431            string[] payloads = chunk.Split(new [] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
 0432            var count = payloads.Length;
 433
 0434            for (int i = 0; i < count; i++)
 435            {
 0436                bool availableMessage = sceneMessagesPool.TryDequeue(out QueuedSceneMessage_Scene freeMessage);
 437
 0438                if (availableMessage)
 439                {
 0440                    EnqueueSceneMessage(Decode(payloads[i], freeMessage));
 441                }
 442                else
 443                {
 0444                    EnqueueSceneMessage(Decode(payloads[i], new QueuedSceneMessage_Scene()));
 445                }
 446            }
 0447        }
 448        private async UniTask WatchForNewChunksToDecode(CancellationToken cancellationToken)
 449        {
 0450            while (!cancellationToken.IsCancellationRequested)
 451            {
 452                try
 453                {
 0454                    if (chunksToDecode.Count > 0)
 455                    {
 0456                        ThreadedDecodeAndEnqueue(cancellationToken);
 457                    }
 0458                }
 459                catch (Exception e)
 460                {
 0461                    Debug.LogException(e);
 0462                }
 463
 0464                await UniTask.Yield();
 465            }
 0466        }
 467        private void ThreadedDecodeAndEnqueue(CancellationToken cancellationToken)
 468        {
 0469            while (chunksToDecode.TryDequeue(out string chunk))
 470            {
 0471                cancellationToken.ThrowIfCancellationRequested();
 472
 0473                string[] payloads = chunk.Split(new [] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
 0474                var count = payloads.Length;
 475
 0476                for (int i = 0; i < count; i++)
 477                {
 0478                    var payload = payloads[i];
 0479                    bool availableMessage = sceneMessagesPool.TryDequeue(out QueuedSceneMessage_Scene freeMessage);
 480
 0481                    if (availableMessage)
 482                    {
 0483                        EnqueueSceneMessage(Decode(payload, freeMessage));
 484                    }
 485                    else
 486                    {
 0487                        EnqueueSceneMessage(Decode(payload, new QueuedSceneMessage_Scene()));
 488                    }
 489                }
 0490            }
 0491        }
 492
 493        public void EnqueueSceneMessage(QueuedSceneMessage_Scene message)
 494        {
 2495            bool isGlobalScene = WorldStateUtils.IsGlobalScene(message.sceneNumber);
 2496            messagingControllersManager.AddControllerIfNotExists(this, message.sceneNumber);
 2497            messagingControllersManager.Enqueue(isGlobalScene, message);
 2498        }
 499
 500        //======================================================================
 501
 502        #endregion
 503
 504        //======================================================================
 505
 506        //======================================================================
 507
 508        #region SCENES_MANAGEMENT
 509
 510        //======================================================================
 511        public event Action<int> OnReadyScene;
 512
 513        public void SendSceneReady(int sceneNumber)
 514        {
 262515            messagingControllersManager.SetSceneReady(sceneNumber);
 516
 262517            WebInterface.ReportControlEvent(new WebInterface.SceneReady(sceneNumber));
 262518            WebInterface.ReportCameraChanged(CommonScriptableObjects.cameraMode.Get(), sceneNumber);
 519
 262520            Environment.i.world.blockersController.SetupWorldBlockers();
 521
 262522            OnReadyScene?.Invoke(sceneNumber);
 0523        }
 524
 525        private void SetPositionDirty(Vector2Int gridPosition, Vector2Int previous)
 526        {
 11527            positionDirty = gridPosition.x != currentGridSceneCoordinate.x || gridPosition.y != currentGridSceneCoordina
 528
 11529            if (positionDirty)
 530            {
 11531                sceneSortDirty = true;
 11532                currentGridSceneCoordinate = gridPosition;
 533
 534                // Since the first position for the character is not sent from Kernel until just-before calling
 535                // the rendering activation from Kernel, we need to sort the scenes to get the current scene id
 536                // to lock the rendering accordingly...
 11537                if (!CommonScriptableObjects.rendererState.Get())
 538                {
 0539                    SortScenesByDistance();
 540                }
 541            }
 11542        }
 543
 544        public void SortScenesByDistance()
 545        {
 515546            IWorldState worldState = Environment.i.world.state;
 547
 515548            worldState.SortScenesByDistance(currentGridSceneCoordinate);
 549
 515550            int currentSceneNumber = worldState.GetCurrentSceneNumber();
 551
 515552            if (!DataStore.i.debugConfig.isDebugMode.Get() && currentSceneNumber <= 0)
 553            {
 554                // When we don't know the current scene yet, we must lock the rendering from enabling until it is set
 503555                CommonScriptableObjects.rendererState.AddLock(this);
 556            }
 557            else
 558            {
 559                // 1. Set current scene id
 12560                CommonScriptableObjects.sceneNumber.Set(currentSceneNumber);
 561
 562                // 2. Attempt to remove SceneController's lock on rendering
 12563                CommonScriptableObjects.rendererState.RemoveLock(this);
 564            }
 565
 515566            OnSortScenes?.Invoke();
 515567        }
 568
 569        private void OnCurrentSceneNumberChange(int newSceneNumber, int previousSceneNumber)
 570        {
 71571            if (Environment.i.world.state.TryGetScene(newSceneNumber, out IParcelScene newCurrentScene)
 572                && !(newCurrentScene as ParcelScene).sceneLifecycleHandler.isReady)
 573            {
 6574                CommonScriptableObjects.rendererState.AddLock(newCurrentScene);
 575
 8576                (newCurrentScene as ParcelScene).sceneLifecycleHandler.OnSceneReady += (readyScene) => { CommonScriptabl
 577            }
 71578        }
 579
 580        public void LoadParcelScenesExecute(string scenePayload)
 581        {
 582            LoadParcelScenesMessage.UnityParcelScene sceneToLoad;
 583
 30584            ProfilingEvents.OnMessageDecodeStart?.Invoke(MessagingTypes.SCENE_LOAD);
 30585            sceneToLoad = Utils.SafeFromJson<LoadParcelScenesMessage.UnityParcelScene>(scenePayload);
 30586            ProfilingEvents.OnMessageDecodeEnds?.Invoke(MessagingTypes.SCENE_LOAD);
 587
 30588            LoadUnityParcelScene(sceneToLoad);
 30589        }
 590
 591        public void LoadUnityParcelScene(LoadParcelScenesMessage.UnityParcelScene sceneToLoad)
 592        {
 33593            if (sceneToLoad == null || sceneToLoad.sceneNumber <= 0)
 0594                return;
 595
 33596            if (VERBOSE)
 0597                Debug.Log($"{Time.frameCount}: Trying to load scene: id: {sceneToLoad.id}; number: {sceneToLoad.sceneNum
 598
 33599            DebugConfig debugConfig = DataStore.i.debugConfig;
 600#if UNITY_EDITOR
 33601            if (debugConfig.soloScene && sceneToLoad.basePosition.ToString() != debugConfig.soloSceneCoords.ToString())
 602            {
 0603                SendSceneReady(sceneToLoad.sceneNumber);
 604
 0605                return;
 606            }
 607#endif
 608
 33609            ProfilingEvents.OnMessageProcessStart?.Invoke(MessagingTypes.SCENE_LOAD);
 610
 33611            IWorldState worldState = Environment.i.world.state;
 612
 33613            if (!worldState.ContainsScene(sceneToLoad.sceneNumber))
 614            {
 33615                var newGameObject = new GameObject("New Scene");
 616
 33617                var newScene = newGameObject.AddComponent<ParcelScene>();
 33618                newScene.SetData(sceneToLoad);
 619
 33620                if (debugConfig.isDebugMode.Get())
 621                {
 28622                    newScene.InitializeDebugPlane();
 623                }
 624
 33625                worldState.AddScene(newScene);
 626
 33627                sceneSortDirty = true;
 628
 33629                OnNewSceneAdded?.Invoke(newScene);
 630
 33631                messagingControllersManager.AddControllerIfNotExists(this, newScene.sceneData.sceneNumber);
 632
 33633                if (VERBOSE)
 0634                    Debug.Log($"{Time.frameCount}: Load parcel scene (id: {newScene.sceneData.sceneNumber})");
 635            }
 636
 33637            ProfilingEvents.OnMessageProcessEnds?.Invoke(MessagingTypes.SCENE_LOAD);
 0638        }
 639
 640        public void UpdateParcelScenesExecute(string scenePayload)
 641        {
 642            LoadParcelScenesMessage.UnityParcelScene sceneData;
 643
 0644            ProfilingEvents.OnMessageDecodeStart?.Invoke(MessagingTypes.SCENE_UPDATE);
 0645            sceneData = Utils.SafeFromJson<LoadParcelScenesMessage.UnityParcelScene>(scenePayload);
 0646            ProfilingEvents.OnMessageDecodeEnds?.Invoke(MessagingTypes.SCENE_UPDATE);
 647
 0648            IWorldState worldState = Environment.i.world.state;
 649
 0650            if (worldState.TryGetScene(sceneData.sceneNumber, out IParcelScene sceneInterface))
 651            {
 0652                ParcelScene scene = sceneInterface as ParcelScene;
 0653                scene.SetUpdateData(sceneData);
 654            }
 655            else
 656            {
 0657                LoadParcelScenesExecute(scenePayload);
 658            }
 0659        }
 660
 661        public void UpdateParcelScenesExecute(LoadParcelScenesMessage.UnityParcelScene scene)
 662        {
 0663            if (scene == null || scene.sceneNumber <= 0)
 0664                return;
 665
 0666            var sceneToLoad = scene;
 667
 0668            ProfilingEvents.OnMessageProcessStart?.Invoke(MessagingTypes.SCENE_UPDATE);
 669
 0670            ParcelScene parcelScene = Environment.i.world.state.GetScene(sceneToLoad.sceneNumber) as ParcelScene;
 671
 0672            if (parcelScene != null)
 0673                parcelScene.SetUpdateData(sceneToLoad);
 674
 0675            ProfilingEvents.OnMessageProcessEnds?.Invoke(MessagingTypes.SCENE_UPDATE);
 0676        }
 677
 678        public void UnloadScene(int sceneNumber)
 679        {
 3680            var queuedMessage = new QueuedSceneMessage()
 681                { type = QueuedSceneMessage.Type.UNLOAD_PARCEL, sceneNumber = sceneNumber };
 682
 3683            ProfilingEvents.OnMessageWillQueue?.Invoke(MessagingTypes.SCENE_DESTROY);
 684
 3685            messagingControllersManager.ForceEnqueueToGlobal(MessagingBusType.INIT, queuedMessage);
 3686            messagingControllersManager.RemoveController(sceneNumber);
 3687        }
 688
 689        public void UnloadParcelSceneExecute(int sceneNumber)
 690        {
 282691            ProfilingEvents.OnMessageProcessStart?.Invoke(MessagingTypes.SCENE_DESTROY);
 692
 282693            IWorldState worldState = Environment.i.world.state;
 694
 282695            if (!worldState.TryGetScene(sceneNumber, out ParcelScene scene))
 0696                return;
 697
 282698            worldState.RemoveScene(sceneNumber);
 699
 282700            DataStore.i.world.portableExperienceIds.Remove(scene.sceneData.id);
 701
 702            // Remove messaging controller for unloaded scene
 282703            messagingControllersManager.RemoveController(sceneNumber);
 704
 282705            scene.Cleanup(!CommonScriptableObjects.rendererState.Get());
 706
 282707            if (VERBOSE)
 708            {
 0709                Debug.Log($"{Time.frameCount} : Destroying scene {scene.sceneData.basePosition}");
 710            }
 711
 282712            Environment.i.world.blockersController.SetupWorldBlockers();
 713
 282714            ProfilingEvents.OnMessageProcessEnds?.Invoke(MessagingTypes.SCENE_DESTROY);
 282715            OnSceneRemoved?.Invoke(scene);
 3716        }
 717
 718        public void UnloadAllScenes(bool includePersistent = false)
 719        {
 514720            var worldState = Environment.i.world.state;
 721
 722            // since the list was changing by this foreach, we make a copy
 514723            var list = worldState.GetLoadedScenes().ToArray();
 724
 1570725            foreach (var kvp in list)
 726            {
 271727                if (kvp.Value.isPersistent && !includePersistent)
 728                    continue;
 729
 271730                UnloadParcelSceneExecute(kvp.Key);
 731            }
 514732        }
 733
 734        public void LoadParcelScenes(string decentralandSceneJSON)
 735        {
 30736            var queuedMessage = new QueuedSceneMessage()
 737            {
 738                type = QueuedSceneMessage.Type.LOAD_PARCEL,
 739                message = decentralandSceneJSON
 740            };
 741
 30742            ProfilingEvents.OnMessageWillQueue?.Invoke(MessagingTypes.SCENE_LOAD);
 743
 30744            messagingControllersManager.ForceEnqueueToGlobal(MessagingBusType.INIT, queuedMessage);
 745
 30746            if (VERBOSE)
 0747                Debug.Log($"{Time.frameCount} : Load parcel scene queue {decentralandSceneJSON}");
 30748        }
 749
 750        public void UpdateParcelScenes(string decentralandSceneJSON)
 751        {
 0752            var queuedMessage = new QueuedSceneMessage()
 753                { type = QueuedSceneMessage.Type.UPDATE_PARCEL, message = decentralandSceneJSON };
 754
 0755            ProfilingEvents.OnMessageWillQueue?.Invoke(MessagingTypes.SCENE_UPDATE);
 756
 0757            messagingControllersManager.ForceEnqueueToGlobal(MessagingBusType.INIT, queuedMessage);
 0758        }
 759
 760        public void UnloadAllScenesQueued()
 761        {
 0762            var queuedMessage = new QueuedSceneMessage() { type = QueuedSceneMessage.Type.UNLOAD_SCENES };
 763
 0764            ProfilingEvents.OnMessageWillQueue?.Invoke(MessagingTypes.SCENE_DESTROY);
 765
 0766            Environment.i.messaging.manager.ForceEnqueueToGlobal(MessagingBusType.INIT, queuedMessage);
 0767        }
 768
 769        public void CreateGlobalScene(CreateGlobalSceneMessage globalScene)
 770        {
 771#if UNITY_EDITOR
 7772            DebugConfig debugConfig = DataStore.i.debugConfig;
 773
 7774            if (debugConfig.soloScene && debugConfig.ignoreGlobalScenes)
 0775                return;
 776#endif
 777
 778            // NOTE(Brian): We should remove this line. SceneController is a runtime core class.
 779            //              It should never have references to UI systems or higher level systems.
 7780            if (globalScene.isPortableExperience && !isPexViewerInitialized.Get())
 781            {
 0782                Debug.LogError(
 783                    "Portable experiences are trying to be added before the system is initialized!. scene number: " +
 784                    globalScene.sceneNumber);
 0785                return;
 786            }
 787
 7788            int newGlobalSceneNumber = globalScene.sceneNumber;
 7789            IWorldState worldState = Environment.i.world.state;
 790
 7791            if (worldState.ContainsScene(newGlobalSceneNumber))
 0792                return;
 793
 7794            var newGameObject = new GameObject("Global Scene - " + newGlobalSceneNumber);
 795
 7796            var newScene = newGameObject.AddComponent<GlobalScene>();
 7797            newScene.unloadWithDistance = false;
 7798            newScene.isPersistent = true;
 7799            newScene.sceneName = globalScene.name;
 7800            newScene.isPortableExperience = globalScene.isPortableExperience;
 801
 7802            LoadParcelScenesMessage.UnityParcelScene sceneData = new LoadParcelScenesMessage.UnityParcelScene
 803            {
 804                id = globalScene.id,
 805                sceneNumber = newGlobalSceneNumber,
 806                basePosition = new Vector2Int(0, 0),
 807                baseUrl = globalScene.baseUrl,
 808                contents = globalScene.contents,
 809                sdk7 = globalScene.sdk7
 810            };
 811
 7812            newScene.SetData(sceneData);
 813
 7814            if (!string.IsNullOrEmpty(globalScene.icon))
 815            {
 0816                newScene.iconUrl = newScene.contentProvider.GetContentsUrl(globalScene.icon);
 817            }
 818
 7819            worldState.AddScene(newScene);
 820
 7821            OnNewSceneAdded?.Invoke(newScene);
 822
 7823            if (newScene.isPortableExperience)
 824            {
 2825                DataStore.i.world.portableExperienceIds.Add(sceneData.id);
 826            }
 827
 7828            messagingControllersManager.AddControllerIfNotExists(this, newGlobalSceneNumber, isGlobal: true);
 829
 7830            if (VERBOSE)
 0831                Debug.Log($"Creating Global scene {newGlobalSceneNumber}");
 7832        }
 833
 834        public void IsolateScene(IParcelScene sceneToActive)
 835        {
 0836            foreach (IParcelScene scene in Environment.i.world.state.GetScenesSortedByDistance())
 837            {
 0838                if (scene != sceneToActive)
 0839                    scene.GetSceneTransform().gameObject.SetActive(false);
 840            }
 0841        }
 842
 843        public void ReIntegrateIsolatedScene()
 844        {
 0845            foreach (IParcelScene scene in Environment.i.world.state.GetScenesSortedByDistance())
 846            {
 0847                scene.GetSceneTransform().gameObject.SetActive(true);
 848            }
 0849        }
 850
 851        //======================================================================
 852
 853        #endregion
 854
 855        //======================================================================
 856
 514857        public ConcurrentQueue<QueuedSceneMessage_Scene> sceneMessagesPool { get; } = new ConcurrentQueue<QueuedSceneMes
 858
 512859        public bool prewarmSceneMessagesPool { get; set; } = true;
 512860        public bool prewarmEntitiesPool { get; set; } = true;
 861
 862        private bool sceneSortDirty = false;
 512863        private bool positionDirty = true;
 864        private int lastSortFrame = 0;
 865
 866        public event Action OnSortScenes;
 867        public event Action<IParcelScene, string> OnOpenExternalUrlRequest;
 868        public event Action<IParcelScene> OnNewSceneAdded;
 869        public event Action<IParcelScene> OnSceneRemoved;
 870
 512871        private Vector2Int currentGridSceneCoordinate = new Vector2Int(EnvironmentSettings.MORDOR_SCALAR, EnvironmentSet
 872    }
 873}

Methods/Properties

enabled()
enabled(System.Boolean)
SceneController()
isPexViewerInitialized()
messagingControllersManager()
entityIdHelper()
Initialize()
SetupDeferredRunners()
PrewarmSceneMessagesPool()
OnDebugModeSet(System.Boolean, System.Boolean)
Dispose()
Update()
LateUpdate()
deferredMessagesDecoding()
deferredMessagesDecoding(System.Boolean)
ProcessMessage(DCL.QueuedSceneMessage_Scene, UnityEngine.CustomYieldInstruction&)
ProcessMessage(DCL.Controllers.ParcelScene, System.String, System.Object, UnityEngine.CustomYieldInstruction&)
ParseQuery(System.Object, System.Int32)
SendSceneMessage(System.String)
Decode(System.String, DCL.QueuedSceneMessage_Scene)
DeferredDecodingAndEnqueue()
EnqueueChunk(System.String)
WatchForNewChunksToDecode()
ThreadedDecodeAndEnqueue(System.Threading.CancellationToken)
EnqueueSceneMessage(DCL.QueuedSceneMessage_Scene)
SendSceneReady(System.Int32)
SetPositionDirty(UnityEngine.Vector2Int, UnityEngine.Vector2Int)
SortScenesByDistance()
OnCurrentSceneNumberChange(System.Int32, System.Int32)
LoadParcelScenesExecute(System.String)
LoadUnityParcelScene(DCL.Models.LoadParcelScenesMessage/UnityParcelScene)
UpdateParcelScenesExecute(System.String)
UpdateParcelScenesExecute(DCL.Models.LoadParcelScenesMessage/UnityParcelScene)
UnloadScene(System.Int32)
UnloadParcelSceneExecute(System.Int32)
UnloadAllScenes(System.Boolean)
LoadParcelScenes(System.String)
UpdateParcelScenes(System.String)
UnloadAllScenesQueued()
CreateGlobalScene(DCL.Models.CreateGlobalSceneMessage)
IsolateScene(DCL.Controllers.IParcelScene)
ReIntegrateIsolatedScene()
sceneMessagesPool()
prewarmSceneMessagesPool()
prewarmSceneMessagesPool(System.Boolean)
prewarmEntitiesPool()
prewarmEntitiesPool(System.Boolean)