< Summary

Class:DCL.Builder.SceneManager
Assembly:BuilderInWorld
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/DCLPlugins/BuilderInWorld/Scripts/SceneManager.cs
Covered lines:174
Uncovered lines:56
Coverable lines:230
Total lines:489
Line coverage:75.6% (174 of 230)
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.025090%
IsParcelSceneDeployedFromSDK(...)0%660100%
EnterEditMode()0%2.012087.5%
ExitEditMode()0%110100%
OpenNewProjectDetails()0%2.062075%
StartFlowWithPermission(...)0%5.25080%
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        {
 9217            foreach (IParcelScene scene in Environment.i.world.state.scenesSortedByDistance)
 218            {
 3219                if (WorldStateUtils.IsCharacterInsideScene(scene))
 3220                    return scene;
 221            }
 222
 0223            return null;
 3224        }
 225
 226        private void UpdateLandsWithAccess()
 227        {
 2228            DeployedScenesFetcher.FetchLandsFromOwner(
 229                                     Environment.i.platform.serviceProviders.catalyst,
 230                                     Environment.i.platform.serviceProviders.theGraph,
 231                                     userProfile.ethAddress,
 232                                     KernelConfig.i.Get().network,
 233                                     BIWSettings.CACHE_TIME_LAND,
 234                                     BIWSettings.CACHE_TIME_SCENES)
 235                                 .Then(lands =>
 236                                 {
 2237                                     DataStore.i.builderInWorld.landsWithAccess.Set(lands.ToArray(), true);
 2238                                     if (isWaitingForPermission && Vector3.Distance(askPermissionLastPosition, DCLCharac
 239                                     {
 1240                                         CheckSceneToEditByShorcut();
 241                                     }
 242
 2243                                     isWaitingForPermission = false;
 2244                                     alreadyAskedForLandPermissions = true;
 2245                                 });
 2246        }
 247
 248        internal void CatalogLoaded()
 249        {
 5250            catalogLoaded = true;
 5251            if ( context.editorContext.editorHUD != null)
 5252                context.editorContext.editorHUD.RefreshCatalogContent();
 5253            NextState();
 5254        }
 255
 256        internal void StartFlow(IParcelScene targetScene, string source, ISceneManager.SceneType sceneType)
 257        {
 1258            if (currentState != State.IDLE || targetScene == null)
 0259                return;
 260
 1261            sceneToEdit = targetScene;
 1262            this.sceneType = sceneType;
 263
 1264            NotificationsController.i.allowNotifications = false;
 1265            CommonScriptableObjects.allUIHidden.Set(true);
 1266            NotificationsController.i.allowNotifications = true;
 1267            inputController.inputTypeMode = InputTypeMode.BUILD_MODE_LOADING;
 268
 269            //We configure the loading part
 1270            initialLoadingController.SetLoadingType(sceneType);
 1271            initialLoadingController.Show();
 1272            initialLoadingController.SetPercentage(0f);
 273
 1274            DataStore.i.appMode.Set(AppMode.BUILDER_IN_WORLD_EDITION);
 1275            DataStore.i.virtualAudioMixer.sceneSFXVolume.Set(0f);
 1276            BIWAnalytics.StartEditorFlow(source);
 1277            beginStartFlowTimeStamp = Time.realtimeSinceStartup;
 278
 1279            context.cameraController.ActivateCamera(sceneToEdit);
 280
 1281            NextState();
 1282        }
 283
 284        internal void GetCatalog()
 285        {
 3286            BIWNFTController.i.StartFetchingNft();
 3287            var catalogPromise = context.builderAPIController.GetCompleteCatalog(userProfile.ethAddress);
 3288            catalogPromise.Then(x =>
 289            {
 3290                CatalogLoaded();
 3291            });
 3292            catalogPromise.Catch(error =>
 293            {
 0294                BIWUtils.ShowGenericNotification(error);
 0295            });
 3296        }
 297
 298        public void ChangeEditModeStatusByShortcut(DCLAction_Trigger action)
 299        {
 1300            if (currentState != State.EDITING && currentState != State.IDLE)
 0301                return;
 302
 1303            if (currentState == State.EDITING )
 304            {
 0305                context.editorContext.editorHUD.ExitStart();
 0306                return;
 307            }
 308
 1309            if (DataStore.i.builderInWorld.landsWithAccess.Get().Length == 0 && !alreadyAskedForLandPermissions)
 310            {
 1311                ActivateLandAccessBackgroundChecker();
 1312                BIWUtils.ShowGenericNotification(BIWSettings.LAND_EDITION_WAITING_FOR_PERMISSIONS_MESSAGE, DCL.Notificat
 1313                isWaitingForPermission = true;
 1314                askPermissionLastPosition = DCLCharacterController.i.characterPosition.unityPosition;
 1315            }
 316            else
 317            {
 0318                CheckSceneToEditByShorcut();
 319            }
 0320        }
 321
 322        internal void CheckSceneToEditByShorcut()
 323        {
 2324            var scene = FindSceneToEdit();
 2325            StartFlowWithPermission(scene, SOURCE_SHORTCUT);
 2326        }
 327
 328        internal void NewSceneAdded(IParcelScene newScene)
 329        {
 1330            if (newScene.sceneData.id != sceneToEditId)
 0331                return;
 332
 1333            Environment.i.world.sceneController.OnNewSceneAdded -= NewSceneAdded;
 334
 1335            sceneToEdit = (ParcelScene)Environment.i.world.state.GetScene(sceneToEditId);
 1336            sceneMetricsAnalyticsHelper = new BiwSceneMetricsAnalyticsHelper(sceneToEdit);
 1337            sceneToEdit.OnLoadingStateUpdated += UpdateSceneLoadingProgress;
 1338        }
 339
 340        private void NewSceneReady(string id)
 341        {
 2342            if (sceneToEditId != id)
 0343                return;
 344
 2345            sceneToEdit.OnLoadingStateUpdated -= UpdateSceneLoadingProgress;
 2346            Environment.i.world.sceneController.OnReadyScene -= NewSceneReady;
 2347            sceneToEditId = null;
 2348            NextState();
 2349        }
 350
 351        internal bool UserHasPermissionOnParcelScene(IParcelScene sceneToCheck)
 352        {
 3353            if (BYPASS_LAND_OWNERSHIP_CHECK)
 0354                return true;
 355
 5356            List<Vector2Int> allParcelsWithAccess = DataStore.i.builderInWorld.landsWithAccess.Get().SelectMany(land => 
 8357            foreach (Vector2Int parcel in allParcelsWithAccess)
 358            {
 4359                if (sceneToCheck.sceneData.parcels.Any(currentParcel => currentParcel.x == parcel.x && currentParcel.y =
 2360                    return true;
 361            }
 362
 1363            return false;
 2364        }
 365
 366        internal bool IsParcelSceneDeployedFromSDK(IParcelScene sceneToCheck)
 367        {
 4368            List<Scene> allDeployedScenesWithAccess = DataStore.i.builderInWorld.landsWithAccess.Get().SelectMany(land =
 5369            foreach (Scene scene in allDeployedScenesWithAccess)
 370            {
 1371                if (scene.source != Scene.Source.SDK)
 372                    continue;
 373
 1374                List<Vector2Int> parcelsDeployedFromSDK = scene.parcels.ToList();
 3375                foreach (Vector2Int parcel in parcelsDeployedFromSDK)
 376                {
 2377                    if (sceneToCheck.sceneData.parcels.Any(currentParcel => currentParcel.x == parcel.x && currentParcel
 1378                        return true;
 379                }
 380            }
 381
 1382            return false;
 1383        }
 384
 385        internal void EnterEditMode()
 386        {
 2387            if (sceneType == ISceneManager.SceneType.DEPLOYED)
 0388                DataStore.i.HUDs.loadingHUD.visible.Set(false);
 389
 2390            initialLoadingController.SetPercentage(100f);
 2391            initialLoadingController.Hide(true, onHideAction: () =>
 392            {
 0393                inputController.inputTypeMode = InputTypeMode.BUILD_MODE;
 0394                context.editorContext.editorHUD?.SetVisibility(true);
 0395                CommonScriptableObjects.allUIHidden.Set(true);
 0396                OpenNewProjectDetails();
 0397            });
 398
 2399            DCLCharacterController.OnPositionSet += ExitAfterCharacterTeleport;
 400
 2401            context.editor.EnterEditMode(sceneToEdit);
 2402            BIWAnalytics.EnterEditor( Time.realtimeSinceStartup - beginStartFlowTimeStamp);
 2403        }
 404
 405        internal void ExitEditMode()
 406        {
 2407            currentState = State.IDLE;
 2408            initialLoadingController.Hide(true);
 2409            inputController.inputTypeMode = InputTypeMode.GENERAL;
 2410            CommonScriptableObjects.allUIHidden.Set(false);
 2411            context.cameraController.DeactivateCamera();
 2412            context.editor.ExitEditMode();
 413
 2414            DCLCharacterController.OnPositionSet -= ExitAfterCharacterTeleport;
 2415        }
 416
 417        internal void OpenNewProjectDetails()
 418        {
 1419            if (!builderInWorldBridge.builderProject.isNewEmptyProject)
 0420                return;
 421
 1422            context.cameraController.TakeSceneScreenshot((sceneSnapshot) =>
 423            {
 0424                context.editorContext.editorHUD?.NewProjectStart(sceneSnapshot);
 0425            });
 1426        }
 427
 428        public void StartFlowWithPermission(IParcelScene targetScene, string source)
 429        {
 4430            if (currentState != State.IDLE || targetScene == null)
 2431                return;
 432
 2433            if (!UserHasPermissionOnParcelScene(targetScene))
 434            {
 1435                BIWUtils.ShowGenericNotification(BIWSettings.LAND_EDITION_NOT_ALLOWED_BY_PERMISSIONS_MESSAGE);
 1436                return;
 437            }
 1438            else if (IsParcelSceneDeployedFromSDK(targetScene))
 439            {
 0440                BIWUtils.ShowGenericNotification(BIWSettings.LAND_EDITION_NOT_ALLOWED_BY_SDK_LIMITATION_MESSAGE);
 0441                return;
 442            }
 443
 1444            StartFlow(targetScene, source, ISceneManager.SceneType.DEPLOYED);
 1445        }
 446
 447        private void LoadScene()
 448        {
 5449            Environment.i.platform.cullingController.Stop();
 450
 5451            sceneToEditId = sceneToEdit.sceneData.id;
 452
 453            // In this point we're sure that the catalog loading (the first half of our progress bar) has already finish
 5454            initialLoadingController.SetPercentage(50f);
 5455            Environment.i.world.sceneController.OnNewSceneAdded += NewSceneAdded;
 5456            Environment.i.world.sceneController.OnReadyScene += NewSceneReady;
 5457            Environment.i.world.blockersController.SetEnabled(false);
 458
 5459            if (sceneType == ISceneManager.SceneType.DEPLOYED)
 1460                builderInWorldBridge.StartKernelEditMode(sceneToEdit);
 5461        }
 462
 463        internal void ActivateLandAccessBackgroundChecker()
 464        {
 2465            userProfile = UserProfile.GetOwnUserProfile();
 2466            if (!string.IsNullOrEmpty(userProfile.userId))
 467            {
 2468                if (updateLandsWithAcessCoroutine != null)
 0469                    CoroutineStarter.Stop(updateLandsWithAcessCoroutine);
 2470                updateLandsWithAcessCoroutine = CoroutineStarter.Start(CheckLandsAccess());
 471            }
 2472        }
 473
 0474        private void UpdateSceneLoadingProgress(float sceneLoadingProgress) { initialLoadingController.SetPercentage(50f
 475
 0476        private void UpdateCatalogLoadingProgress(float catalogLoadingProgress) { initialLoadingController.SetPercentage
 477
 2478        internal void ExitAfterCharacterTeleport(DCLCharacterPosition position) { ExitEditMode(); }
 479
 480        private IEnumerator CheckLandsAccess()
 481        {
 0482            while (true)
 483            {
 2484                UpdateLandsWithAccess();
 2485                yield return WaitForSecondsCache.Get(BIWSettings.REFRESH_LANDS_WITH_ACCESS_INTERVAL);
 486            }
 487        }
 488    }
 489}