< Summary

Class:DCL.SceneController
Assembly:DCL.Runtime
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/WorldRuntime/SceneController.cs
Covered lines:199
Uncovered lines:178
Coverable lines:377
Total lines:939
Line coverage:52.7% (199 of 377)
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%3.713057.14%
Dispose()0%220100%
Update()0%440100%
LateUpdate()0%220100%
ProcessMessage(...)0%1101000%
ProcessMessage(...)0%27565200%
ParseQuery(...)0%6200%
SendSceneMessage(...)0%6200%
Decode(...)0%20400%
DeferredDecodingAndEnqueue()0%10.378066.67%
EnqueueChunk(...)0%12300%
WatchForNewChunksToDecode()0%30500%
ThreadedDecodeAndEnqueue(...)0%20400%
EnqueueSceneMessage(...)0%2100%
SendSceneReady(...)0%220100%
ActivateBuilderInWorldEditScene()0%110100%
DeactivateBuilderInWorldEditScene()0%110100%
SetPositionDirty(...)0%4.054085.71%
SortScenesByDistance()0%770100%
SortScenesByDistanceMethod(...)0%110100%
OnCurrentSceneIdChange(...)0%64050%
LoadParcelScenesExecute(...)0%14.8214083.87%
UpdateParcelScenesExecute(...)0%20400%
UpdateParcelScenesExecute(...)0%6.396077.78%
UnloadScene(...)0%220100%
UnloadParcelSceneExecute(...)0%7.147085.71%
UnloadAllScenes(...)0%440100%
LoadParcelScenes(...)0%3.043083.33%
UpdateParcelScenes(...)0%6200%
UnloadAllScenesQueued()0%6200%
CreateGlobalScene(...)0%10.810080%
IsolateScene(...)0%330100%
ReIntegrateIsolatedScene()0%220100%

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
 70725        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;
 90933        private IMessagingControllersManager messagingControllersManager => Environment.i.messaging.manager;
 34
 71635        public EntityIdHelper entityIdHelper { get; } = new EntityIdHelper();
 36
 37        public void Initialize()
 38        {
 68339            tokenSource = new CancellationTokenSource();
 68340            sceneSortDirty = true;
 68341            positionDirty = true;
 68342            lastSortFrame = 0;
 68343            enabled = true;
 44
 68345            loadingFeedbackController = new LoadingFeedbackController();
 46
 68347            DataStore.i.debugConfig.isDebugMode.OnChange += OnDebugModeSet;
 48
 68349            SetupDeferredRunners();
 50
 68351            DataStore.i.player.playerGridPosition.OnChange += SetPositionDirty;
 68352            CommonScriptableObjects.sceneID.OnChange += OnCurrentSceneIdChange;
 53
 54            // TODO(Brian): Move this later to Main.cs
 68355            if ( !EnvironmentSettings.RUNNING_TESTS )
 56            {
 057                PrewarmSceneMessagesPool();
 58            }
 59
 68360            Environment.i.platform.updateEventHandler.AddListener(IUpdateEventHandler.EventType.Update, Update);
 68361            Environment.i.platform.updateEventHandler.AddListener(IUpdateEventHandler.EventType.LateUpdate, LateUpdate);
 68362        }
 63        private void SetupDeferredRunners()
 64        {
 65#if UNITY_WEBGL
 68366            deferredDecodingCoroutine = CoroutineStarter.Start(DeferredDecodingAndEnqueue());
 67#else
 68            CancellationToken tokenSourceToken = tokenSource.Token;
 69            TaskUtils.Run(async () => await WatchForNewChunksToDecode(tokenSourceToken), cancellationToken: tokenSourceT
 70#endif
 68371        }
 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        {
 1291            if (current == previous)
 092                return;
 93
 1294            if (current)
 95            {
 1296                Environment.i.world.sceneBoundsChecker.SetFeedbackStyle(new SceneBoundsFeedbackStyle_RedBox());
 1297            }
 98            else
 99            {
 0100                Environment.i.world.sceneBoundsChecker.SetFeedbackStyle(new SceneBoundsFeedbackStyle_Simple());
 101            }
 0102        }
 103
 104        public void Dispose()
 105        {
 683106            tokenSource.Cancel();
 683107            tokenSource.Dispose();
 683108            loadingFeedbackController.Dispose();
 109
 683110            Environment.i.platform.updateEventHandler.RemoveListener(IUpdateEventHandler.EventType.Update, Update);
 683111            Environment.i.platform.updateEventHandler.RemoveListener(IUpdateEventHandler.EventType.LateUpdate, LateUpdat
 112
 683113            PoolManager.i.OnGet -= Environment.i.platform.physicsSyncController.MarkDirty;
 683114            PoolManager.i.OnGet -= Environment.i.platform.cullingController.objectsTracker.MarkDirty;
 115
 683116            DataStore.i.player.playerGridPosition.OnChange -= SetPositionDirty;
 683117            DataStore.i.debugConfig.isDebugMode.OnChange -= OnDebugModeSet;
 118
 683119            CommonScriptableObjects.sceneID.OnChange -= OnCurrentSceneIdChange;
 120
 683121            UnloadAllScenes(includePersistent: true);
 122
 683123            if (deferredDecodingCoroutine != null)
 683124                CoroutineStarter.Stop(deferredDecodingCoroutine);
 683125        }
 126
 127        public void Update()
 128        {
 6952129            if (!enabled)
 406130                return;
 131
 6546132            if (lastSortFrame != Time.frameCount && sceneSortDirty)
 133            {
 677134                lastSortFrame = Time.frameCount;
 677135                sceneSortDirty = false;
 677136                SortScenesByDistance();
 137            }
 6546138        }
 139
 140        public void LateUpdate()
 141        {
 6952142            if (!enabled)
 406143                return;
 144
 6546145            Environment.i.platform.physicsSyncController.Sync();
 6546146        }
 147
 148        //======================================================================
 149
 150        #region MESSAGES_HANDLING
 151
 152        //======================================================================
 153
 154#if UNITY_EDITOR
 155        public delegate void ProcessDelegate(string sceneId, string method);
 156
 157        public event ProcessDelegate OnMessageProcessInfoStart;
 158        public event ProcessDelegate OnMessageProcessInfoEnds;
 159#endif
 0160        public bool deferredMessagesDecoding { get; set; } = false;
 161
 683162        readonly ConcurrentQueue<string> chunksToDecode = new ConcurrentQueue<string>();
 683163        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        {
 0169            string sceneId = msgObject.sceneId;
 0170            string method = msgObject.method;
 171
 0172            yieldInstruction = null;
 173
 174            IParcelScene scene;
 0175            bool res = false;
 0176            IWorldState worldState = Environment.i.world.state;
 0177            DebugConfig debugConfig = DataStore.i.debugConfig;
 178
 0179            if (worldState.loadedScenes.TryGetValue(sceneId, out scene))
 180            {
 181#if UNITY_EDITOR
 0182                if (debugConfig.soloScene && scene is GlobalScene && debugConfig.ignoreGlobalScenes)
 183                {
 0184                    return false;
 185                }
 186#endif
 0187                if (!scene.GetSceneTransform().gameObject.activeInHierarchy)
 188                {
 0189                    return true;
 190                }
 191
 192#if UNITY_EDITOR
 0193                OnMessageProcessInfoStart?.Invoke(sceneId, method);
 194#endif
 0195                ProfilingEvents.OnMessageProcessStart?.Invoke(method);
 196
 0197                ProcessMessage(scene as ParcelScene, method, msgObject.payload, out yieldInstruction);
 198
 0199                ProfilingEvents.OnMessageProcessEnds?.Invoke(method);
 200
 201#if UNITY_EDITOR
 0202                OnMessageProcessInfoEnds?.Invoke(sceneId, method);
 203#endif
 204
 0205                res = true;
 0206            }
 207
 208            else
 209            {
 0210                res = false;
 211            }
 212
 0213            sceneMessagesPool.Enqueue(msgObject);
 214
 0215            return res;
 216        }
 217
 218        private void ProcessMessage(ParcelScene scene, string method, object msgPayload,
 219            out CustomYieldInstruction yieldInstruction)
 220        {
 0221            yieldInstruction = null;
 0222            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                        {
 0308                            scene.sceneLifecycleHandler.SetInitMessagesDone();
 309
 0310                            break;
 311                        }
 312
 313                    case MessagingTypes.QUERY:
 314                        {
 0315                            if (msgPayload is QueryMessage queryMessage)
 0316                                ParseQuery(queryMessage.payload, scene.sceneData.id);
 317
 0318                            break;
 319                        }
 320
 321                    case MessagingTypes.OPEN_EXTERNAL_URL:
 322                        {
 0323                            if (msgPayload is Protocol.OpenExternalUrl payload)
 0324                                OnOpenExternalUrlRequest?.Invoke(scene, payload.url);
 325
 0326                            break;
 327                        }
 328
 329                    case MessagingTypes.OPEN_NFT_DIALOG:
 330                        {
 0331                            if (msgPayload is Protocol.OpenNftDialog payload)
 0332                                DataStore.i.common.onOpenNFTPrompt.Set(new NFTPromptModel(payload.contactAddress, payloa
 333                                    payload.comment), true);
 334
 0335                            break;
 336                        }
 337
 338                    case MessagingTypes.CRDT_MESSAGE:
 339                        {
 0340                            if (msgPayload is CRDTMessage crdtMessage)
 341                            {
 0342                                scene.crdtExecutor?.Execute(crdtMessage);
 343                            }
 0344                            break;
 345                        }
 346
 347                    default:
 0348                        Debug.LogError($"Unknown method {method}");
 349
 350                        break;
 351                }
 0352            }
 0353            catch (Exception e)
 354            {
 0355                throw new Exception(
 356                    $"Scene message error. scene: {scene.sceneData.id} method: {method} payload: {JsonUtility.ToJson(msg
 357            }
 358
 0359            if (delayedComponent != null)
 360            {
 0361                if (delayedComponent.isRoutineRunning)
 0362                    yieldInstruction = delayedComponent.yieldInstruction;
 363            }
 0364        }
 365
 366        public void ParseQuery(object payload, string sceneId)
 367        {
 0368            IParcelScene scene = Environment.i.world.state.loadedScenes[sceneId];
 369
 0370            if (!(payload is RaycastQuery raycastQuery))
 0371                return;
 372
 0373            Vector3 worldOrigin = raycastQuery.ray.origin + Utils.GridToWorldPosition(scene.sceneData.basePosition.x, sc
 374
 0375            raycastQuery.ray.unityOrigin = PositionUtils.WorldToUnityPosition(worldOrigin);
 0376            raycastQuery.sceneId = sceneId;
 0377            PhysicsCast.i.Query(raycastQuery, entityIdHelper);
 0378        }
 379
 380        public void SendSceneMessage(string chunk)
 381        {
 0382            var renderer = CommonScriptableObjects.rendererState.Get();
 383
 0384            if (!renderer)
 385            {
 0386                EnqueueChunk(chunk);
 0387            }
 388            else
 389            {
 0390                chunksToDecode.Enqueue(chunk);
 391            }
 0392        }
 393
 394        private QueuedSceneMessage_Scene Decode(string payload, QueuedSceneMessage_Scene queuedMessage)
 395        {
 0396            ProfilingEvents.OnMessageDecodeStart?.Invoke("Misc");
 397
 0398            if (!MessageDecoder.DecodePayloadChunk(payload,
 399                    out string sceneId,
 400                    out string message,
 401                    out string messageTag,
 402                    out PB_SendSceneMessage sendSceneMessage))
 403            {
 0404                return null;
 405            }
 406
 0407            MessageDecoder.DecodeSceneMessage(sceneId, message, messageTag, sendSceneMessage, ref queuedMessage);
 408
 0409            ProfilingEvents.OnMessageDecodeEnds?.Invoke("Misc");
 410
 0411            return queuedMessage;
 412        }
 413
 414        private IEnumerator DeferredDecodingAndEnqueue()
 415        {
 683416            float start = Time.realtimeSinceStartup;
 417            float maxTimeForDecode;
 418
 7144419            while (true)
 420            {
 7827421                maxTimeForDecode = CommonScriptableObjects.rendererState.Get() ? MAX_TIME_FOR_DECODE : float.MaxValue;
 422
 7827423                if (chunksToDecode.Count > 0)
 424                {
 0425                    if (chunksToDecode.TryDequeue(out string chunk))
 426                    {
 0427                        EnqueueChunk(chunk);
 428
 0429                        if (Time.realtimeSinceStartup - start < maxTimeForDecode)
 430                            continue;
 431                    }
 432                }
 433
 7827434                yield return null;
 435
 7144436                start = Time.unscaledTime;
 437            }
 438        }
 439        private void EnqueueChunk(string chunk)
 440        {
 0441            string[] payloads = chunk.Split(new [] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
 0442            var count = payloads.Length;
 443
 0444            for (int i = 0; i < count; i++)
 445            {
 0446                bool availableMessage = sceneMessagesPool.TryDequeue(out QueuedSceneMessage_Scene freeMessage);
 447
 0448                if (availableMessage)
 449                {
 0450                    EnqueueSceneMessage(Decode(payloads[i], freeMessage));
 0451                }
 452                else
 453                {
 0454                    EnqueueSceneMessage(Decode(payloads[i], new QueuedSceneMessage_Scene()));
 455                }
 456            }
 0457        }
 458        private async UniTask WatchForNewChunksToDecode(CancellationToken cancellationToken)
 459        {
 0460            while (!cancellationToken.IsCancellationRequested)
 461            {
 462                try
 463                {
 0464                    if (chunksToDecode.Count > 0)
 465                    {
 0466                        ThreadedDecodeAndEnqueue(cancellationToken);
 467                    }
 0468                }
 469                catch (Exception e)
 470                {
 0471                    Debug.LogException(e);
 0472                }
 473
 0474                await UniTask.Yield();
 475            }
 0476        }
 477        private void ThreadedDecodeAndEnqueue(CancellationToken cancellationToken)
 478        {
 0479            while (chunksToDecode.TryDequeue(out string chunk))
 480            {
 0481                cancellationToken.ThrowIfCancellationRequested();
 482
 0483                string[] payloads = chunk.Split(new [] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
 0484                var count = payloads.Length;
 485
 0486                for (int i = 0; i < count; i++)
 487                {
 0488                    var payload = payloads[i];
 0489                    bool availableMessage = sceneMessagesPool.TryDequeue(out QueuedSceneMessage_Scene freeMessage);
 490
 0491                    if (availableMessage)
 492                    {
 0493                        EnqueueSceneMessage(Decode(payload, freeMessage));
 0494                    }
 495                    else
 496                    {
 0497                        EnqueueSceneMessage(Decode(payload, new QueuedSceneMessage_Scene()));
 498                    }
 499                }
 0500            }
 0501        }
 502
 503        public void EnqueueSceneMessage(QueuedSceneMessage_Scene message)
 504        {
 0505            bool isGlobalScene = WorldStateUtils.IsGlobalScene(message.sceneId);
 0506            messagingControllersManager.AddControllerIfNotExists(this, message.sceneId);
 0507            messagingControllersManager.Enqueue(isGlobalScene, message);
 0508        }
 509
 510        //======================================================================
 511
 512        #endregion
 513
 514        //======================================================================
 515
 516        //======================================================================
 517
 518        #region SCENES_MANAGEMENT
 519
 520        //======================================================================
 521        public event Action<string> OnReadyScene;
 522
 523        public void SendSceneReady(string sceneId)
 524        {
 411525            Environment.i.world.state.readyScenes.Add(sceneId);
 526
 411527            messagingControllersManager.SetSceneReady(sceneId);
 528
 411529            WebInterface.ReportControlEvent(new WebInterface.SceneReady(sceneId));
 411530            WebInterface.ReportCameraChanged(CommonScriptableObjects.cameraMode.Get(), sceneId);
 531
 411532            Environment.i.world.blockersController.SetupWorldBlockers();
 533
 411534            OnReadyScene?.Invoke(sceneId);
 2535        }
 536
 10537        public void ActivateBuilderInWorldEditScene() { Environment.i.world.sceneBoundsChecker.SetFeedbackStyle(new Scen
 538
 2539        public void DeactivateBuilderInWorldEditScene() { Environment.i.world.sceneBoundsChecker.SetFeedbackStyle(new Sc
 540
 541        private void SetPositionDirty(Vector2Int gridPosition, Vector2Int previous)
 542        {
 12543            positionDirty = gridPosition.x != currentGridSceneCoordinate.x || gridPosition.x != currentGridSceneCoordina
 544
 12545            if (positionDirty)
 546            {
 12547                sceneSortDirty = true;
 12548                currentGridSceneCoordinate = gridPosition;
 549
 550                // Since the first position for the character is not sent from Kernel until just-before calling
 551                // the rendering activation from Kernel, we need to sort the scenes to get the current scene id
 552                // to lock the rendering accordingly...
 12553                if (!CommonScriptableObjects.rendererState.Get())
 554                {
 0555                    SortScenesByDistance();
 556                }
 557            }
 12558        }
 559
 560        public void SortScenesByDistance()
 561        {
 562            // if (DCLCharacterController.i == null)
 563            //     return;
 564
 677565            IWorldState worldState = Environment.i.world.state;
 566
 677567            worldState.currentSceneId = null;
 677568            worldState.scenesSortedByDistance.Sort(SortScenesByDistanceMethod);
 569
 677570            using (var iterator = Environment.i.world.state.scenesSortedByDistance.GetEnumerator())
 571            {
 572                IParcelScene scene;
 573                bool characterIsInsideScene;
 574
 700575                while (iterator.MoveNext())
 576                {
 28577                    scene = iterator.Current;
 578
 28579                    if (scene == null)
 580                        continue;
 581
 28582                    characterIsInsideScene = WorldStateUtils.IsCharacterInsideScene(scene);
 28583                    bool isGlobalScene = worldState.globalSceneIds.Contains(scene.sceneData.id);
 584
 28585                    if (!isGlobalScene && characterIsInsideScene)
 586                    {
 5587                        worldState.currentSceneId = scene.sceneData.id;
 588
 5589                        break;
 590                    }
 591                }
 672592            }
 593
 677594            if (!DataStore.i.debugConfig.isDebugMode.Get() && string.IsNullOrEmpty(worldState.currentSceneId))
 595            {
 596                // When we don't know the current scene yet, we must lock the rendering from enabling until it is set
 669597                CommonScriptableObjects.rendererState.AddLock(this);
 669598            }
 599            else
 600            {
 601                // 1. Set current scene id
 8602                CommonScriptableObjects.sceneID.Set(worldState.currentSceneId);
 603
 604                // 2. Attempt to remove SceneController's lock on rendering
 8605                CommonScriptableObjects.rendererState.RemoveLock(this);
 606            }
 607
 677608            OnSortScenes?.Invoke();
 677609        }
 610
 611        private int SortScenesByDistanceMethod(IParcelScene sceneA, IParcelScene sceneB)
 612        {
 59613            sortAuxiliaryVector = sceneA.sceneData.basePosition - currentGridSceneCoordinate;
 59614            int dist1 = sortAuxiliaryVector.sqrMagnitude;
 615
 59616            sortAuxiliaryVector = sceneB.sceneData.basePosition - currentGridSceneCoordinate;
 59617            int dist2 = sortAuxiliaryVector.sqrMagnitude;
 618
 59619            return dist1 - dist2;
 620        }
 621
 622        private void OnCurrentSceneIdChange(string newSceneId, string prevSceneId)
 623        {
 20624            if (Environment.i.world.state.TryGetScene(newSceneId, out IParcelScene newCurrentScene)
 625                && !(newCurrentScene as ParcelScene).sceneLifecycleHandler.isReady)
 626            {
 0627                CommonScriptableObjects.rendererState.AddLock(newCurrentScene);
 628
 0629                (newCurrentScene as ParcelScene).sceneLifecycleHandler.OnSceneReady += (readyScene) => { CommonScriptabl
 630            }
 20631        }
 632
 633        public void LoadParcelScenesExecute(string scenePayload)
 634        {
 635            LoadParcelScenesMessage.UnityParcelScene scene;
 636
 26637            ProfilingEvents.OnMessageDecodeStart?.Invoke(MessagingTypes.SCENE_LOAD);
 26638            scene = Utils.SafeFromJson<LoadParcelScenesMessage.UnityParcelScene>(scenePayload);
 26639            ProfilingEvents.OnMessageDecodeEnds?.Invoke(MessagingTypes.SCENE_LOAD);
 640
 26641            if (scene == null || scene.id == null)
 0642                return;
 643
 26644            var sceneToLoad = scene;
 645
 26646            DebugConfig debugConfig = DataStore.i.debugConfig;
 647#if UNITY_EDITOR
 26648            if (debugConfig.soloScene && sceneToLoad.basePosition.ToString() != debugConfig.soloSceneCoords.ToString())
 649            {
 0650                SendSceneReady(sceneToLoad.id);
 651
 0652                return;
 653            }
 654#endif
 655
 26656            ProfilingEvents.OnMessageProcessStart?.Invoke(MessagingTypes.SCENE_LOAD);
 657
 26658            IWorldState worldState = Environment.i.world.state;
 659
 26660            if (!worldState.loadedScenes.ContainsKey(sceneToLoad.id))
 661            {
 26662                var newGameObject = new GameObject("New Scene");
 663
 26664                var newScene = newGameObject.AddComponent<ParcelScene>();
 26665                newScene.SetData(sceneToLoad);
 666
 26667                if (debugConfig.isDebugMode.Get())
 668                {
 26669                    newScene.InitializeDebugPlane();
 670                }
 671
 26672                worldState.loadedScenes.Add(sceneToLoad.id, newScene);
 673
 120674                foreach (Vector2Int sceneParcel in newScene.parcels)
 675                {
 34676                    worldState.loadedScenesByCoordinate.Add(sceneParcel, sceneToLoad.id);
 677                }
 678
 26679                worldState.scenesSortedByDistance.Add(newScene);
 680
 26681                sceneSortDirty = true;
 682
 26683                OnNewSceneAdded?.Invoke(newScene);
 684
 26685                messagingControllersManager.AddControllerIfNotExists(this, newScene.sceneData.id);
 686
 26687                if (VERBOSE)
 0688                    Debug.Log($"{Time.frameCount}: Load parcel scene (id: {newScene.sceneData.id})");
 689            }
 690
 26691            ProfilingEvents.OnMessageProcessEnds?.Invoke(MessagingTypes.SCENE_LOAD);
 0692        }
 693
 694        public void UpdateParcelScenesExecute(string sceneId)
 695        {
 696            LoadParcelScenesMessage.UnityParcelScene sceneData;
 697
 0698            ProfilingEvents.OnMessageDecodeStart?.Invoke(MessagingTypes.SCENE_UPDATE);
 0699            sceneData = Utils.SafeFromJson<LoadParcelScenesMessage.UnityParcelScene>(sceneId);
 0700            ProfilingEvents.OnMessageDecodeEnds?.Invoke(MessagingTypes.SCENE_UPDATE);
 701
 0702            IWorldState worldState = Environment.i.world.state;
 703
 0704            if (worldState.TryGetScene(sceneData.id, out IParcelScene sceneInterface))
 705            {
 0706                ParcelScene scene = sceneInterface as ParcelScene;
 0707                scene.SetUpdateData(sceneData);
 0708            }
 709            else
 710            {
 0711                LoadParcelScenesExecute(sceneId);
 712            }
 0713        }
 714
 715        public void UpdateParcelScenesExecute(LoadParcelScenesMessage.UnityParcelScene scene)
 716        {
 15717            if (scene == null || scene.id == null)
 0718                return;
 719
 15720            var sceneToLoad = scene;
 721
 15722            ProfilingEvents.OnMessageProcessStart?.Invoke(MessagingTypes.SCENE_UPDATE);
 723
 15724            ParcelScene parcelScene = Environment.i.world.state.GetScene(sceneToLoad.id) as ParcelScene;
 725
 15726            if (parcelScene != null)
 15727                parcelScene.SetUpdateData(sceneToLoad);
 728
 15729            ProfilingEvents.OnMessageProcessEnds?.Invoke(MessagingTypes.SCENE_UPDATE);
 0730        }
 731
 732        public void UnloadScene(string sceneKey)
 733        {
 1734            var queuedMessage = new QueuedSceneMessage()
 735                { type = QueuedSceneMessage.Type.UNLOAD_PARCEL, message = sceneKey };
 736
 1737            ProfilingEvents.OnMessageWillQueue?.Invoke(MessagingTypes.SCENE_DESTROY);
 738
 1739            messagingControllersManager.ForceEnqueueToGlobal(MessagingBusType.INIT, queuedMessage);
 1740            messagingControllersManager.RemoveController(sceneKey);
 1741        }
 742
 743        public void UnloadParcelSceneExecute(string sceneId)
 744        {
 439745            ProfilingEvents.OnMessageProcessStart?.Invoke(MessagingTypes.SCENE_DESTROY);
 746
 439747            IWorldState worldState = Environment.i.world.state;
 748
 439749            if (!worldState.Contains(sceneId))
 0750                return;
 751
 439752            ParcelScene scene = (ParcelScene) worldState.loadedScenes[sceneId];
 753
 439754            worldState.loadedScenes.Remove(sceneId);
 439755            worldState.globalSceneIds.Remove(sceneId);
 756
 1762757            foreach (Vector2Int sceneParcel in scene.parcels)
 758            {
 442759                worldState.loadedScenesByCoordinate.Remove(sceneParcel);
 760            }
 761
 439762            DataStore.i.world.portableExperienceIds.Remove(sceneId);
 763
 764            // Remove the scene id from the msg. priorities list
 439765            worldState.scenesSortedByDistance.Remove(scene);
 766
 767            // Remove messaging controller for unloaded scene
 439768            messagingControllersManager.RemoveController(scene.sceneData.id);
 769
 439770            scene.Cleanup(!CommonScriptableObjects.rendererState.Get());
 771
 439772            if (VERBOSE)
 773            {
 0774                Debug.Log($"{Time.frameCount} : Destroying scene {scene.sceneData.basePosition}");
 775            }
 776
 439777            Environment.i.world.blockersController.SetupWorldBlockers();
 778
 439779            ProfilingEvents.OnMessageProcessEnds?.Invoke(MessagingTypes.SCENE_DESTROY);
 439780            OnSceneRemoved?.Invoke(scene);
 0781        }
 782
 783        public void UnloadAllScenes(bool includePersistent = false)
 784        {
 685785            var worldState = Environment.i.world.state;
 786
 685787            var list = worldState.loadedScenes.ToArray();
 788
 2240789            for (int i = 0; i < list.Length; i++)
 790            {
 435791                if (list[i].Value.isPersistent && !includePersistent)
 792                    continue;
 793
 435794                UnloadParcelSceneExecute(list[i].Key);
 795            }
 685796        }
 797
 798        public void LoadParcelScenes(string decentralandSceneJSON)
 799        {
 26800            var queuedMessage = new QueuedSceneMessage()
 801            {
 802                type = QueuedSceneMessage.Type.LOAD_PARCEL,
 803                message = decentralandSceneJSON
 804            };
 805
 26806            ProfilingEvents.OnMessageWillQueue?.Invoke(MessagingTypes.SCENE_LOAD);
 807
 26808            messagingControllersManager.ForceEnqueueToGlobal(MessagingBusType.INIT, queuedMessage);
 809
 26810            if (VERBOSE)
 0811                Debug.Log($"{Time.frameCount} : Load parcel scene queue {decentralandSceneJSON}");
 26812        }
 813
 814        public void UpdateParcelScenes(string decentralandSceneJSON)
 815        {
 0816            var queuedMessage = new QueuedSceneMessage()
 817                { type = QueuedSceneMessage.Type.UPDATE_PARCEL, message = decentralandSceneJSON };
 818
 0819            ProfilingEvents.OnMessageWillQueue?.Invoke(MessagingTypes.SCENE_UPDATE);
 820
 0821            messagingControllersManager.ForceEnqueueToGlobal(MessagingBusType.INIT, queuedMessage);
 0822        }
 823
 824        public void UnloadAllScenesQueued()
 825        {
 0826            var queuedMessage = new QueuedSceneMessage() { type = QueuedSceneMessage.Type.UNLOAD_SCENES };
 827
 0828            ProfilingEvents.OnMessageWillQueue?.Invoke(MessagingTypes.SCENE_DESTROY);
 829
 0830            Environment.i.messaging.manager.ForceEnqueueToGlobal(MessagingBusType.INIT, queuedMessage);
 0831        }
 832
 833        public void CreateGlobalScene(string json)
 834        {
 835#if UNITY_EDITOR
 5836            DebugConfig debugConfig = DataStore.i.debugConfig;
 837
 5838            if (debugConfig.soloScene && debugConfig.ignoreGlobalScenes)
 0839                return;
 840#endif
 5841            CreateGlobalSceneMessage globalScene = Utils.SafeFromJson<CreateGlobalSceneMessage>(json);
 842
 843            // NOTE(Brian): We should remove this line. SceneController is a runtime core class.
 844            //              It should never have references to UI systems or higher level systems.
 5845            if (globalScene.isPortableExperience && !isPexViewerInitialized.Get())
 846            {
 0847                Debug.LogError(
 848                    "Portable experiences are trying to be added before the system is initialized!. SceneID: " +
 849                    globalScene.id);
 0850                return;
 851            }
 852
 5853            string newGlobalSceneId = globalScene.id;
 854
 5855            IWorldState worldState = Environment.i.world.state;
 856
 5857            if (worldState.loadedScenes.ContainsKey(newGlobalSceneId))
 0858                return;
 859
 5860            var newGameObject = new GameObject("Global Scene - " + newGlobalSceneId);
 861
 5862            var newScene = newGameObject.AddComponent<GlobalScene>();
 5863            newScene.unloadWithDistance = false;
 5864            newScene.isPersistent = true;
 5865            newScene.sceneName = globalScene.name;
 5866            newScene.isPortableExperience = globalScene.isPortableExperience;
 867
 5868            LoadParcelScenesMessage.UnityParcelScene data = new LoadParcelScenesMessage.UnityParcelScene
 869            {
 870                id = newGlobalSceneId,
 871                basePosition = new Vector2Int(0, 0),
 872                baseUrl = globalScene.baseUrl,
 873                contents = globalScene.contents
 874            };
 875
 5876            newScene.SetData(data);
 877
 5878            if (!string.IsNullOrEmpty(globalScene.icon))
 879            {
 0880                newScene.iconUrl = newScene.contentProvider.GetContentsUrl(globalScene.icon);
 881            }
 882
 5883            worldState.loadedScenes.Add(newGlobalSceneId, newScene);
 5884            OnNewSceneAdded?.Invoke(newScene);
 885
 5886            if (newScene.isPortableExperience)
 887            {
 2888                DataStore.i.world.portableExperienceIds.Add(newGlobalSceneId);
 889            }
 890
 5891            worldState.globalSceneIds.Add(newGlobalSceneId);
 892
 5893            messagingControllersManager.AddControllerIfNotExists(this, newGlobalSceneId, isGlobal: true);
 894
 5895            if (VERBOSE)
 0896                Debug.Log($"Creating Global scene {newGlobalSceneId}");
 5897        }
 898
 899        public void IsolateScene(IParcelScene sceneToActive)
 900        {
 156901            foreach (IParcelScene scene in Environment.i.world.state.scenesSortedByDistance)
 902            {
 39903                if (scene != sceneToActive)
 5904                    scene.GetSceneTransform().gameObject.SetActive(false);
 905            }
 39906        }
 907
 908        public void ReIntegrateIsolatedScene()
 909        {
 20910            foreach (IParcelScene scene in Environment.i.world.state.scenesSortedByDistance)
 911            {
 5912                scene.GetSceneTransform().gameObject.SetActive(true);
 913            }
 5914        }
 915
 916        //======================================================================
 917
 918        #endregion
 919
 920        //======================================================================
 921
 683922        public ConcurrentQueue<QueuedSceneMessage_Scene> sceneMessagesPool { get; } = new ConcurrentQueue<QueuedSceneMes
 923
 683924        public bool prewarmSceneMessagesPool { get; set; } = true;
 683925        public bool prewarmEntitiesPool { get; set; } = true;
 926
 927        private bool sceneSortDirty = false;
 683928        private bool positionDirty = true;
 929        private int lastSortFrame = 0;
 930
 931        public event Action OnSortScenes;
 932        public event Action<IParcelScene, string> OnOpenExternalUrlRequest;
 933        public event Action<IParcelScene> OnNewSceneAdded;
 934        public event Action<IParcelScene> OnSceneRemoved;
 935
 683936        private Vector2Int currentGridSceneCoordinate = new Vector2Int(EnvironmentSettings.MORDOR_SCALAR, EnvironmentSet
 683937        private Vector2Int sortAuxiliaryVector = new Vector2Int(EnvironmentSettings.MORDOR_SCALAR, EnvironmentSettings.M
 938    }
 939}

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.String)
SendSceneMessage(System.String)
Decode(System.String, DCL.QueuedSceneMessage_Scene)
DeferredDecodingAndEnqueue()
EnqueueChunk(System.String)
WatchForNewChunksToDecode()
ThreadedDecodeAndEnqueue(System.Threading.CancellationToken)
EnqueueSceneMessage(DCL.QueuedSceneMessage_Scene)
SendSceneReady(System.String)
ActivateBuilderInWorldEditScene()
DeactivateBuilderInWorldEditScene()
SetPositionDirty(UnityEngine.Vector2Int, UnityEngine.Vector2Int)
SortScenesByDistance()
SortScenesByDistanceMethod(DCL.Controllers.IParcelScene, DCL.Controllers.IParcelScene)
OnCurrentSceneIdChange(System.String, System.String)
LoadParcelScenesExecute(System.String)
UpdateParcelScenesExecute(System.String)
UpdateParcelScenesExecute(DCL.Models.LoadParcelScenesMessage/UnityParcelScene)
UnloadScene(System.String)
UnloadParcelSceneExecute(System.String)
UnloadAllScenes(System.Boolean)
LoadParcelScenes(System.String)
UpdateParcelScenes(System.String)
UnloadAllScenesQueued()
CreateGlobalScene(System.String)
IsolateScene(DCL.Controllers.IParcelScene)
ReIntegrateIsolatedScene()
sceneMessagesPool()
prewarmSceneMessagesPool()
prewarmSceneMessagesPool(System.Boolean)
prewarmEntitiesPool()
prewarmEntitiesPool(System.Boolean)