< Summary

Class:DCL.Builder.SceneManager
Assembly:BuilderInWorld
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/DCLPlugins/BuilderInWorld/Scripts/SceneManager.cs
Covered lines:167
Uncovered lines:65
Coverable lines:232
Total lines:492
Line coverage:71.9% (167 of 232)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
Initialize(...)0%110100%
Dispose()0%550100%
ConfigureLoadingController()0%110100%
NextState()0%770100%
WebRequestCreated(...)0%6200%
Update()0%30500%
OnPlayerTeleportedToEditScene(...)0%2100%
StartEditorFromManifest(...)0%2100%
TakeSceneScreenshotForPublish()0%2100%
StartExitMode()0%3.213071.43%
FindSceneToEdit()0%3.033085.71%
UpdateLandsWithAccess()0%110100%
CatalogLoaded()0%220100%
StartFlow(...)0%33094.44%
GetCatalog()0%220100%
ChangeEditModeStatusByShortcut(...)0%8.056061.54%
CheckSceneToEditByShorcut()0%110100%
NewSceneAdded(...)0%2.012085.71%
NewSceneReady(...)0%2.012085.71%
UserHasPermissionOnParcelScene(...)0%5.25080%
IsParcelSceneDeployedFromSDK(...)0%660100%
EnterEditMode()0%2.012087.5%
ExitEditMode()0%110100%
OpenNewProjectDetails()0%2.062075%
StartFlowWithPermission(...)0%6.65060%
LoadScene()0%220100%
ActivateLandAccessBackgroundChecker()0%3.043083.33%
UpdateSceneLoadingProgress(...)0%2100%
UpdateCatalogLoadingProgress(...)0%2100%
ExitAfterCharacterTeleport(...)0%110100%
CheckLandsAccess()0%3.333066.67%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/DCLPlugins/BuilderInWorld/Scripts/SceneManager.cs

#LineLine coverage
 1using System;
 2using System.Collections;
 3using System.Collections.Generic;
 4using System.Linq;
 5using DCL.Camera;
 6using DCL.Configuration;
 7using DCL.Controllers;
 8using UnityEngine;
 9
 10namespace DCL.Builder
 11{
 12    public class SceneManager : ISceneManager
 13    {
 14        internal static bool BYPASS_LAND_OWNERSHIP_CHECK = false;
 15        private const float MAX_DISTANCE_STOP_TRYING_TO_ENTER = 16;
 16
 17        private const string SOURCE_BUILDER_PANEl = "BuilderPanel";
 18        private const string SOURCE_SHORTCUT = "Shortcut";
 19
 20        public enum State
 21        {
 22            IDLE = 0,
 23            LOADING_CATALOG = 1,
 24            CATALOG_LOADED = 2,
 25            PREPARE_SCENE = 3,
 26            LOADING_SCENE = 4,
 27            SCENE_LOADED = 5,
 28            EDITING = 6
 29        }
 30
 31        internal State currentState = State.IDLE;
 32        public ISceneManager.SceneType sceneType = ISceneManager.SceneType.PROJECT;
 33
 34        private InputAction_Trigger editModeChangeInputAction;
 35
 36        internal IContext context;
 37        internal string sceneToEditId;
 38        private UserProfile userProfile;
 39        internal Coroutine updateLandsWithAcessCoroutine;
 40
 41        private bool alreadyAskedForLandPermissions = false;
 42        private Vector3 askPermissionLastPosition;
 43        private IWebRequestAsyncOperation catalogAsyncOp;
 44        internal bool isWaitingForPermission = false;
 45        internal IParcelScene sceneToEdit;
 46        private BiwSceneMetricsAnalyticsHelper sceneMetricsAnalyticsHelper;
 47        private InputController inputController;
 48        internal BuilderInWorldBridge builderInWorldBridge;
 49        internal IBuilderInWorldLoadingController initialLoadingController;
 50        private float beginStartFlowTimeStamp = 0;
 51
 52        internal bool catalogLoaded = false;
 53        internal Manifest.Manifest currentManifest;
 54
 55        public void Initialize(IContext context)
 56        {
 1457            this.context = context;
 1458            editModeChangeInputAction = context.inputsReferencesAsset.editModeChangeInputAction;
 1459            editModeChangeInputAction.OnTriggered += ChangeEditModeStatusByShortcut;
 1460            inputController = context.sceneReferences.inputController;
 61
 62
 1463            builderInWorldBridge = context.sceneReferences.biwBridgeGameObject.GetComponent<BuilderInWorldBridge>();
 1464            userProfile = UserProfile.GetOwnUserProfile();
 65
 66
 1467            context.editorContext.editorHUD.OnPublishAction += TakeSceneScreenshotForPublish;
 1468            context.editorContext.editorHUD.OnStartExitAction += StartExitMode;
 1469            context.editorContext.editorHUD.OnLogoutAction += ExitEditMode;
 70
 1471            BIWTeleportAndEdit.OnTeleportEnd += OnPlayerTeleportedToEditScene;
 1472            context.builderAPIController.OnWebRequestCreated += WebRequestCreated;
 73
 1474            ConfigureLoadingController();
 1475        }
 76
 77        public void Dispose()
 78        {
 1479            if (context.editorContext.editorHUD != null)
 80            {
 1481                context.editorContext.editorHUD.OnPublishAction -= TakeSceneScreenshotForPublish;
 1482                context.editorContext.editorHUD.OnStartExitAction -= StartExitMode;
 1483                context.editorContext.editorHUD.OnLogoutAction -= ExitEditMode;
 84            }
 85
 1486            sceneMetricsAnalyticsHelper?.Dispose();
 87
 1488            initialLoadingController?.Dispose();
 89
 1490            Environment.i.world.sceneController.OnNewSceneAdded -= NewSceneAdded;
 1491            Environment.i.world.sceneController.OnReadyScene -= NewSceneReady;
 1492            BIWTeleportAndEdit.OnTeleportEnd -= OnPlayerTeleportedToEditScene;
 1493            DCLCharacterController.OnPositionSet -= ExitAfterCharacterTeleport;
 94
 1495            if (sceneToEdit != null)
 796                sceneToEdit.OnLoadingStateUpdated -= UpdateSceneLoadingProgress;
 97
 1498            editModeChangeInputAction.OnTriggered -= ChangeEditModeStatusByShortcut;
 1499            context.builderAPIController.OnWebRequestCreated -= WebRequestCreated;
 100
 14101            CoroutineStarter.Stop(updateLandsWithAcessCoroutine);
 14102        }
 103
 104        private void ConfigureLoadingController()
 105        {
 14106            initialLoadingController = new BuilderInWorldLoadingController();
 14107            initialLoadingController.Initialize();
 14108        }
 109
 110        public void NextState()
 111        {
 21112            currentState++;
 21113            switch (currentState)
 114            {
 115                case State.LOADING_CATALOG:
 4116                    if (!catalogLoaded)
 1117                        GetCatalog();
 118                    else
 3119                        NextState();
 3120                    break;
 121
 122                case State.CATALOG_LOADED:
 5123                    NextState();
 5124                    break;
 125
 126                //TODO: This step wil be implemented in the future
 127                case State.PREPARE_SCENE:
 5128                    NextState();
 5129                    break;
 130
 131                case State.LOADING_SCENE:
 5132                    LoadScene();
 5133                    break;
 134
 135                case State.SCENE_LOADED:
 2136                    EnterEditMode();
 137                    break;
 138            }
 2139        }
 140
 141        public void WebRequestCreated(IWebRequestAsyncOperation webRequest)
 142        {
 0143            if (currentState == State.LOADING_CATALOG)
 0144                catalogAsyncOp = webRequest;
 0145        }
 146
 147        public void Update()
 148        {
 0149            if (currentState != State.LOADING_CATALOG)
 0150                return;
 151
 0152            if (catalogAsyncOp?.webRequest != null)
 0153                UpdateCatalogLoadingProgress(catalogAsyncOp.webRequest.downloadProgress * 100);
 0154        }
 155
 156        private void OnPlayerTeleportedToEditScene(Vector2Int coords)
 157        {
 0158            var targetScene = Environment.i.world.state.scenesSortedByDistance
 0159                .FirstOrDefault(scene => scene.sceneData.parcels.Contains(coords));
 0160            StartFlowWithPermission(targetScene, SOURCE_BUILDER_PANEl);
 0161        }
 162
 163        public void StartEditorFromManifest(Manifest.Manifest manifest)
 164        {
 0165            DataStore.i.HUDs.loadingHUD.visible.Set(true);
 166
 167            //We set the manifest for future saves
 0168            currentManifest = manifest;
 0169            context.editorContext.saveController.SetManifest(manifest);
 170
 0171            ParcelScene convertedScene = ManifestTranslator.TranslateManifestToScene(manifest);
 0172            StartFlow(convertedScene, SOURCE_BUILDER_PANEl, ISceneManager.SceneType.PROJECT);
 0173        }
 174
 175        internal void TakeSceneScreenshotForPublish()
 176        {
 0177            context.cameraController.TakeSceneScreenshot((sceneSnapshot) =>
 178            {
 0179                context.editorContext.editorHUD?.SetBuilderProjectScreenshot(sceneSnapshot);
 0180            });
 0181        }
 182
 183        public void StartExitMode()
 184        {
 1185            if (context.editorContext.saveController.GetSaveTimes() > 0)
 186            {
 1187                context.cameraController.TakeSceneScreenshotFromResetPosition((sceneSnapshot) =>
 188                {
 0189                    if (sceneSnapshot != null)
 190                    {
 191                        //This should dissapear when we migrate completely the scene lifecycle to unity
 0192                        context.editorContext.editorHUD?.SaveSceneInfo();
 0193                        if (currentManifest != null)
 0194                            context.builderAPIController.SetThumbnail(currentManifest.project.id, sceneSnapshot);
 195                    }
 0196                });
 197
 1198                if (context.editorContext.editorHUD != null)
 1199                    context.editorContext.editorHUD.ConfigureConfirmationModal(
 200                        BIWSettings.EXIT_MODAL_TITLE,
 201                        BIWSettings.EXIT_WITHOUT_PUBLISH_MODAL_SUBTITLE,
 202                        BIWSettings.EXIT_WITHOUT_PUBLISH_MODAL_CANCEL_BUTTON,
 203                        BIWSettings.EXIT_WITHOUT_PUBLISH_MODAL_CONFIRM_BUTTON);
 1204            }
 205            else
 206            {
 0207                context.editorContext.editorHUD.ConfigureConfirmationModal(
 208                    BIWSettings.EXIT_MODAL_TITLE,
 209                    BIWSettings.EXIT_MODAL_SUBTITLE,
 210                    BIWSettings.EXIT_MODAL_CANCEL_BUTTON,
 211                    BIWSettings.EXIT_MODAL_CONFIRM_BUTTON);
 212            }
 0213        }
 214
 215        public IParcelScene FindSceneToEdit()
 216        {
 6217            foreach (IParcelScene scene in Environment.i.world.state.scenesSortedByDistance)
 218            {
 2219                if (WorldStateUtils.IsCharacterInsideScene(scene))
 2220                    return scene;
 221            }
 222
 0223            return null;
 2224        }
 225
 226        private void UpdateLandsWithAccess()
 227        {
 2228            ICatalyst catalyst = Environment.i.platform.serviceProviders.catalyst;
 2229            ITheGraph theGraph = Environment.i.platform.serviceProviders.theGraph;
 230
 2231            DeployedScenesFetcher.FetchLandsFromOwner(
 232                    catalyst,
 233                    theGraph,
 234                    userProfile.ethAddress,
 235                    KernelConfig.i.Get().network,
 236                    BIWSettings.CACHE_TIME_LAND,
 237                    BIWSettings.CACHE_TIME_SCENES)
 238                .Then(lands =>
 239                {
 0240                    DataStore.i.builderInWorld.landsWithAccess.Set(lands.ToArray(), true);
 0241                    if (isWaitingForPermission && Vector3.Distance(askPermissionLastPosition, DCLCharacterController.i.c
 242                    {
 0243                        CheckSceneToEditByShorcut();
 244                    }
 245
 0246                    isWaitingForPermission = false;
 0247                    alreadyAskedForLandPermissions = true;
 0248                });
 2249        }
 250
 251        internal void CatalogLoaded()
 252        {
 5253            catalogLoaded = true;
 5254            if ( context.editorContext.editorHUD != null)
 5255                context.editorContext.editorHUD.RefreshCatalogContent();
 5256            NextState();
 5257        }
 258
 259        internal void StartFlow(IParcelScene targetScene, string source, ISceneManager.SceneType sceneType)
 260        {
 1261            if (currentState != State.IDLE || targetScene == null)
 0262                return;
 263
 1264            sceneToEdit = targetScene;
 1265            this.sceneType = sceneType;
 266
 1267            NotificationsController.i.allowNotifications = false;
 1268            CommonScriptableObjects.allUIHidden.Set(true);
 1269            NotificationsController.i.allowNotifications = true;
 1270            inputController.inputTypeMode = InputTypeMode.BUILD_MODE_LOADING;
 271
 272            //We configure the loading part
 1273            initialLoadingController.SetLoadingType(sceneType);
 1274            initialLoadingController.Show();
 1275            initialLoadingController.SetPercentage(0f);
 276
 1277            DataStore.i.common.appMode.Set(AppMode.BUILDER_IN_WORLD_EDITION);
 1278            DataStore.i.virtualAudioMixer.sceneSFXVolume.Set(0f);
 1279            BIWAnalytics.StartEditorFlow(source);
 1280            beginStartFlowTimeStamp = Time.realtimeSinceStartup;
 281
 1282            context.cameraController.ActivateCamera(sceneToEdit);
 283
 1284            NextState();
 1285        }
 286
 287        internal void GetCatalog()
 288        {
 3289            BIWNFTController.i.StartFetchingNft();
 3290            var catalogPromise = context.builderAPIController.GetCompleteCatalog(userProfile.ethAddress);
 3291            catalogPromise.Then(x =>
 292            {
 3293                CatalogLoaded();
 3294            });
 3295            catalogPromise.Catch(error =>
 296            {
 0297                BIWUtils.ShowGenericNotification(error);
 0298            });
 3299        }
 300
 301        public void ChangeEditModeStatusByShortcut(DCLAction_Trigger action)
 302        {
 1303            if (currentState != State.EDITING && currentState != State.IDLE)
 0304                return;
 305
 1306            if (currentState == State.EDITING )
 307            {
 0308                context.editorContext.editorHUD.ExitStart();
 0309                return;
 310            }
 311
 1312            if (DataStore.i.builderInWorld.landsWithAccess.Get().Length == 0 && !alreadyAskedForLandPermissions)
 313            {
 1314                ActivateLandAccessBackgroundChecker();
 1315                BIWUtils.ShowGenericNotification(BIWSettings.LAND_EDITION_WAITING_FOR_PERMISSIONS_MESSAGE, DCL.Notificat
 1316                isWaitingForPermission = true;
 1317                askPermissionLastPosition = DCLCharacterController.i.characterPosition.unityPosition;
 1318            }
 319            else
 320            {
 0321                CheckSceneToEditByShorcut();
 322            }
 0323        }
 324
 325        internal void CheckSceneToEditByShorcut()
 326        {
 1327            var scene = FindSceneToEdit();
 1328            StartFlowWithPermission(scene, SOURCE_SHORTCUT);
 1329        }
 330
 331        internal void NewSceneAdded(IParcelScene newScene)
 332        {
 1333            if (newScene.sceneData.id != sceneToEditId)
 0334                return;
 335
 1336            Environment.i.world.sceneController.OnNewSceneAdded -= NewSceneAdded;
 337
 1338            sceneToEdit = (ParcelScene)Environment.i.world.state.GetScene(sceneToEditId);
 1339            sceneMetricsAnalyticsHelper = new BiwSceneMetricsAnalyticsHelper(sceneToEdit);
 1340            sceneToEdit.OnLoadingStateUpdated += UpdateSceneLoadingProgress;
 1341        }
 342
 343        private void NewSceneReady(string id)
 344        {
 2345            if (sceneToEditId != id)
 0346                return;
 347
 2348            sceneToEdit.OnLoadingStateUpdated -= UpdateSceneLoadingProgress;
 2349            Environment.i.world.sceneController.OnReadyScene -= NewSceneReady;
 2350            sceneToEditId = null;
 2351            NextState();
 2352        }
 353
 354        internal bool UserHasPermissionOnParcelScene(IParcelScene sceneToCheck)
 355        {
 2356            if (BYPASS_LAND_OWNERSHIP_CHECK)
 0357                return true;
 358
 4359            List<Vector2Int> allParcelsWithAccess = DataStore.i.builderInWorld.landsWithAccess.Get().SelectMany(land => 
 6360            foreach (Vector2Int parcel in allParcelsWithAccess)
 361            {
 4362                if (sceneToCheck.sceneData.parcels.Any(currentParcel => currentParcel.x == parcel.x && currentParcel.y =
 2363                    return true;
 364            }
 365
 0366            return false;
 2367        }
 368
 369        internal bool IsParcelSceneDeployedFromSDK(IParcelScene sceneToCheck)
 370        {
 4371            List<Scene> allDeployedScenesWithAccess = DataStore.i.builderInWorld.landsWithAccess.Get().SelectMany(land =
 5372            foreach (Scene scene in allDeployedScenesWithAccess)
 373            {
 1374                if (scene.source != Scene.Source.SDK)
 375                    continue;
 376
 1377                List<Vector2Int> parcelsDeployedFromSDK = scene.parcels.ToList();
 3378                foreach (Vector2Int parcel in parcelsDeployedFromSDK)
 379                {
 2380                    if (sceneToCheck.sceneData.parcels.Any(currentParcel => currentParcel.x == parcel.x && currentParcel
 1381                        return true;
 382                }
 383            }
 384
 1385            return false;
 1386        }
 387
 388        internal void EnterEditMode()
 389        {
 2390            if (sceneType == ISceneManager.SceneType.DEPLOYED)
 0391                DataStore.i.HUDs.loadingHUD.visible.Set(false);
 392
 2393            initialLoadingController.SetPercentage(100f);
 2394            initialLoadingController.Hide(true, onHideAction: () =>
 395            {
 0396                inputController.inputTypeMode = InputTypeMode.BUILD_MODE;
 0397                context.editorContext.editorHUD?.SetVisibility(true);
 0398                CommonScriptableObjects.allUIHidden.Set(true);
 0399                OpenNewProjectDetails();
 0400            });
 401
 2402            DCLCharacterController.OnPositionSet += ExitAfterCharacterTeleport;
 403
 2404            context.editor.EnterEditMode(sceneToEdit);
 2405            BIWAnalytics.EnterEditor( Time.realtimeSinceStartup - beginStartFlowTimeStamp);
 2406        }
 407
 408        internal void ExitEditMode()
 409        {
 2410            currentState = State.IDLE;
 2411            initialLoadingController.Hide(true);
 2412            inputController.inputTypeMode = InputTypeMode.GENERAL;
 2413            CommonScriptableObjects.allUIHidden.Set(false);
 2414            context.cameraController.DeactivateCamera();
 2415            context.editor.ExitEditMode();
 416
 2417            DCLCharacterController.OnPositionSet -= ExitAfterCharacterTeleport;
 2418        }
 419
 420        internal void OpenNewProjectDetails()
 421        {
 1422            if (!builderInWorldBridge.builderProject.isNewEmptyProject)
 0423                return;
 424
 1425            context.cameraController.TakeSceneScreenshot((sceneSnapshot) =>
 426            {
 0427                context.editorContext.editorHUD?.NewProjectStart(sceneSnapshot);
 0428            });
 1429        }
 430
 431        public void StartFlowWithPermission(IParcelScene targetScene, string source)
 432        {
 3433            if (currentState != State.IDLE || targetScene == null)
 2434                return;
 435
 1436            if (!UserHasPermissionOnParcelScene(targetScene))
 437            {
 0438                BIWUtils.ShowGenericNotification(BIWSettings.LAND_EDITION_NOT_ALLOWED_BY_PERMISSIONS_MESSAGE);
 0439                return;
 440            }
 1441            else if (IsParcelSceneDeployedFromSDK(targetScene))
 442            {
 0443                BIWUtils.ShowGenericNotification(BIWSettings.LAND_EDITION_NOT_ALLOWED_BY_SDK_LIMITATION_MESSAGE);
 0444                return;
 445            }
 446
 1447            StartFlow(targetScene, source, ISceneManager.SceneType.DEPLOYED);
 1448        }
 449
 450        private void LoadScene()
 451        {
 5452            Environment.i.platform.cullingController.Stop();
 453
 5454            sceneToEditId = sceneToEdit.sceneData.id;
 455
 456            // In this point we're sure that the catalog loading (the first half of our progress bar) has already finish
 5457            initialLoadingController.SetPercentage(50f);
 5458            Environment.i.world.sceneController.OnNewSceneAdded += NewSceneAdded;
 5459            Environment.i.world.sceneController.OnReadyScene += NewSceneReady;
 5460            Environment.i.world.blockersController.SetEnabled(false);
 461
 5462            if (sceneType == ISceneManager.SceneType.DEPLOYED)
 1463                builderInWorldBridge.StartKernelEditMode(sceneToEdit);
 5464        }
 465
 466        internal void ActivateLandAccessBackgroundChecker()
 467        {
 2468            userProfile = UserProfile.GetOwnUserProfile();
 2469            if (!string.IsNullOrEmpty(userProfile.userId))
 470            {
 2471                if (updateLandsWithAcessCoroutine != null)
 0472                    CoroutineStarter.Stop(updateLandsWithAcessCoroutine);
 2473                updateLandsWithAcessCoroutine = CoroutineStarter.Start(CheckLandsAccess());
 474            }
 2475        }
 476
 0477        private void UpdateSceneLoadingProgress(float sceneLoadingProgress) { initialLoadingController.SetPercentage(50f
 478
 0479        private void UpdateCatalogLoadingProgress(float catalogLoadingProgress) { initialLoadingController.SetPercentage
 480
 2481        internal void ExitAfterCharacterTeleport(DCLCharacterPosition position) { ExitEditMode(); }
 482
 483        private IEnumerator CheckLandsAccess()
 484        {
 0485            while (true)
 486            {
 2487                UpdateLandsWithAccess();
 2488                yield return WaitForSecondsCache.Get(BIWSettings.REFRESH_LANDS_WITH_ACCESS_INTERVAL);
 489            }
 490        }
 491    }
 492}