< Summary

Class:DCL.Builder.Publisher
Assembly:BuilderPublisher
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/DCLPlugins/BuilderInWorld/Publisher/Scripts/Publisher.cs
Covered lines:0
Uncovered lines:202
Coverable lines:202
Total lines:470
Line coverage:0% (0 of 202)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
Initialize(...)0%6200%
Dispose()0%6200%
BackToPublishInfo()0%12300%
StartPublish(...)0%56700%
Unpublish()0%30500%
Canceled()0%2100%
HasLands()0%2100%
CanPublishInLands(...)0%2100%
PublishLandScene(...)0%2100%
ConfirmDeployment(...)0%2100%
StartDeployment()0%2100%
ApplyRotation(...)0%2100%
UndoRotationToScene(...)0%2100%
RotationScene(...)0%6200%
DeployScene()0%30500%
StartUnpublishScene(...)0%2100%
StartPublishScene(...)0%6200%
PublishEnd(...)0%56700%
CreateSceneJson(...)0%12300%
DownloadAssetFiles()0%1321100%

File(s)

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

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using Cysharp.Threading.Tasks;
 5using DCL.Builder.Manifest;
 6using DCL.Configuration;
 7using DCL.Helpers;
 8using DCL.Interface;
 9using UnityEngine;
 10
 11namespace DCL.Builder
 12{
 13    public class Publisher : IPublisher
 14    {
 15        private const string BIGGER_LAND_TO_PUBLISH_TEXT = "Your scene is bigger than any Land you own.\nBrowse the Mark
 16        private const string NO_LAND_TO_PUBLISH_TEXT = "To publish a scene first you need a Land where you can deploy it
 17        public const string UNPUBLISH_EMPTY_SCENE_NAME = "Empty";
 18
 19        public enum TYPE
 20        {
 21            PUBLISH = 0,
 22            UNPUBLISH = 1
 23        }
 24        public event Action<bool> OnPublishFinish;
 25
 26        private IPublishProjectController projectPublisher;
 27        private ILandPublisherController landPublisher;
 28        private IPublishProgressController progressController;
 29
 30        private IContext context;
 31
 32        private BuilderInWorldBridge builderInWorldBridge;
 33        private float startPublishingTimestamp = 0;
 34
 35        private IBuilderScene builderSceneToDeploy;
 36        private PublishInfo publishInfo;
 37        private IBuilderScene.SceneType lastTypeWhoStartedPublish;
 38        private TYPE type = TYPE.PUBLISH;
 39
 40        private float rotationToApply = 0f;
 41
 42        public void Initialize(IContext context)
 43        {
 044            this.context = context;
 45
 046            projectPublisher = new PublishProjectController();
 047            landPublisher = new LandPublisherController();
 048            progressController = new PublishProgressController();
 49
 050            landPublisher.Initialize();
 051            projectPublisher.Initialize();
 052            progressController.Initialize();
 53
 054            landPublisher.OnPublishPressed += PublishLandScene;
 055            projectPublisher.OnPublishPressed += ConfirmDeployment;
 56
 057            landPublisher.OnPublishCancel += Canceled;
 058            projectPublisher.OnPublishCancel += Canceled;
 59
 060            progressController.OnConfirm += StartDeployment;
 061            progressController.OnBackPressed += BackToPublishInfo;
 62
 063            builderInWorldBridge = context.sceneReferences.biwBridgeGameObject.GetComponent<BuilderInWorldBridge>();
 64
 065            if (builderInWorldBridge != null)
 066                builderInWorldBridge.OnPublishEnd += PublishEnd;
 067        }
 68
 69        public void Dispose()
 70        {
 071            landPublisher.OnPublishPressed -= PublishLandScene;
 072            projectPublisher.OnPublishPressed -= ConfirmDeployment;
 73
 074            landPublisher.OnPublishCancel -= Canceled;
 075            projectPublisher.OnPublishCancel -= Canceled;
 76
 077            progressController.OnConfirm -= StartDeployment;
 078            progressController.OnBackPressed -= BackToPublishInfo;
 79
 080            if (builderInWorldBridge != null)
 081                builderInWorldBridge.OnPublishEnd -= PublishEnd;
 82
 083            projectPublisher.Dispose();
 084            landPublisher.Dispose();
 085            progressController.Dispose();
 086        }
 87
 88        private void BackToPublishInfo()
 89        {
 090            switch (lastTypeWhoStartedPublish)
 91            {
 92                case IBuilderScene.SceneType.PROJECT:
 093                    projectPublisher.SetActive(true);
 094                    break;
 95                case IBuilderScene.SceneType.LAND:
 096                    landPublisher.SetActive(true);
 97                    break;
 98            }
 099        }
 100
 101        public void StartPublish(IBuilderScene scene)
 102        {
 0103            if (!HasLands())
 104            {
 0105                context.commonHUD.GetPopUp()
 106                       .ShowPopUpWithoutTitle(NO_LAND_TO_PUBLISH_TEXT, "BUY LAND", "BACK", () =>
 107                       {
 0108                           WebInterface.OpenURL(BIWSettings.MARKETPLACE_URL);
 0109                       }, null);
 0110                return;
 111            }
 112
 0113            if (!CanPublishInLands(scene))
 114            {
 0115                context.commonHUD.GetPopUp()
 116                       .ShowPopUpWithoutTitle(BIGGER_LAND_TO_PUBLISH_TEXT, "BUY LAND", "BACK", () =>
 117                       {
 0118                           WebInterface.OpenURL(BIWSettings.MARKETPLACE_URL);
 0119                       }, null);
 0120                return;
 121            }
 122
 0123            DataStore.i.builderInWorld.areShortcutsBlocked.Set(true);
 0124            type = TYPE.PUBLISH;
 125
 0126            switch (scene.sceneType)
 127            {
 128                case IBuilderScene.SceneType.PROJECT:
 0129                    projectPublisher.StartPublishFlow(scene);
 0130                    break;
 131                case IBuilderScene.SceneType.LAND:
 0132                    landPublisher.StartPublishFlow(scene);
 133                    break;
 134            }
 135
 0136            lastTypeWhoStartedPublish = scene.sceneType;
 0137        }
 138
 139        public async void Unpublish(Vector2Int coords, Vector2Int size)
 140        {
 0141            type = TYPE.UNPUBLISH;
 142
 0143            var manifest = BIWUtils.CreateEmptyDefaultBuilderManifest(size, BIWUtils.Vector2INTToString(coords));
 144
 0145            CatalystSceneEntityMetadata sceneJson = new CatalystSceneEntityMetadata();
 146
 147            //Display info
 0148            sceneJson.display = new CatalystSceneEntityMetadata.Display();
 0149            sceneJson.display.title = UNPUBLISH_EMPTY_SCENE_NAME;
 150
 151            //Scenes
 0152            sceneJson.scene = new CatalystSceneEntityMetadata.Scene();
 153
 154            //  Base Parcels
 0155            string baseParcels = BIWUtils.Vector2INTToString(coords);
 0156            sceneJson.scene.@base = baseParcels;
 157
 158            //  All parcels
 0159            string[] parcels = new string[size.x*size.y];
 0160            int count = 0;
 161
 0162            for (int x = 0; x < size.x; x++)
 163            {
 0164                for (int y = 0; y < size.y; y++)
 165                {
 0166                    parcels[count] = (coords.x + x) + "," + (coords.y + y);
 0167                    count++;
 168                }
 169            }
 170
 0171            sceneJson.scene.parcels = parcels;
 172
 173            //Main
 0174            sceneJson.main = BIWSettings.DEPLOYMENT_BUNDLED_GAME_FILE;
 175
 176            //Source
 0177            sceneJson.source = new CatalystSceneEntityMetadata.Source();
 0178            sceneJson.source.origin = BIWSettings.DEPLOYMENT_SOURCE_TYPE;
 0179            sceneJson.source.version = 1;
 0180            sceneJson.source.layout = new CatalystSceneEntityMetadata.Source.Layout();
 0181            sceneJson.source.layout.rows = size.x;
 0182            sceneJson.source.layout.cols = size.y;
 0183            sceneJson.source.point = new CatalystSceneEntityMetadata.Vector2IntRepresentantion(coords);
 0184            sceneJson.source.isEmpty = true;
 0185            sceneJson.source.isEmpty = true;
 186
 187            // Prepare the assets
 0188            List<SceneObject> assets = manifest.scene.assets.Values.ToList();
 189
 190            // Download the assets files
 0191            Dictionary<string, object> downloadedFiles = await DownloadAssetFiles(assets);
 192
 193            // This files are not encoded
 0194            Dictionary<string, object> entityFiles = new Dictionary<string, object>
 195            {
 196                { BIWSettings.DEPLOYMENT_SCENE_FILE, sceneJson },
 197                { BIWSettings.DEPLOYMENT_ASSETS, assets },
 198            };
 199
 200            // Prepare the stateless manifest
 0201            StatelessManifest statelessManifest = ManifestTranslator.WebBuilderSceneToStatelessManifest(manifest.scene);
 202
 203            // Sent scene to kernel
 0204            StartUnpublishScene(downloadedFiles,entityFiles,statelessManifest, sceneJson);
 0205        }
 206
 207        internal void Canceled()
 208        {
 0209            DataStore.i.builderInWorld.areShortcutsBlocked.Set(false);
 0210        }
 211
 0212        internal bool HasLands() { return DataStore.i.builderInWorld.landsWithAccess.Get().Length > 0; }
 213
 214        internal bool CanPublishInLands(IBuilderScene scene)
 215        {
 0216            List<Vector2Int> availableLandsToPublish = BIWUtils.GetLandsToPublishProject(DataStore.i.builderInWorld.land
 0217            return availableLandsToPublish.Count > 0;
 218        }
 219
 220        internal void PublishLandScene(IBuilderScene scene)
 221        {
 0222            PublishInfo publishInfo = new PublishInfo();
 0223            publishInfo.rotation = PublishInfo.ProjectRotation.NORTH;
 0224            publishInfo.coordsToPublish = scene.landCoordsAsociated;
 0225            ConfirmDeployment(scene, publishInfo);
 0226        }
 227
 228        internal void ConfirmDeployment(IBuilderScene scene, PublishInfo info)
 229        {
 0230            builderSceneToDeploy = scene;
 0231            publishInfo = info;
 0232            progressController.SetInfoToPublish(scene, info);
 0233            progressController.ShowConfirmDeploy();
 0234        }
 235
 0236        internal void StartDeployment() { DeployScene(builderSceneToDeploy, publishInfo); }
 237
 238        internal void ApplyRotation(IBuilderScene scene, PublishInfo.ProjectRotation rotation)
 239        {
 0240            rotationToApply = 90f * (int)rotation;
 0241            RotationScene(scene, rotationToApply);
 0242        }
 243
 244        internal void UndoRotationToScene(IBuilderScene scene)
 245        {
 0246            RotationScene(scene, -rotationToApply);
 0247        }
 248
 249        internal void RotationScene(IBuilderScene scene, float amount)
 250        {
 251            // Note: if the aerialscreenshot is not available, this means that the scene has been deployed
 252            // from the panel instead of the editor, so we don't have the scene to rotate, we publish it to north direct
 0253            if (scene.aerialScreenshotTexture == null)
 0254                return;
 255
 0256            var transform = scene.scene.GetSceneTransform();
 0257            Vector3 middlePoint = BIWUtils.CalculateUnityMiddlePoint(scene.scene);
 258
 0259            transform.RotateAround(middlePoint,Vector3.up,amount);
 0260            scene.UpdateManifestFromScene();
 0261        }
 262
 263        internal async void DeployScene(IBuilderScene scene, PublishInfo info)
 264        {
 265            try
 266            {
 267                // We assign the scene to deploy
 0268                builderSceneToDeploy = scene;
 269
 270                // Prepare the thumbnail
 0271                byte[] thumbnail = scene.sceneScreenshotTexture.EncodeToPNG();
 272
 273                // Prepare the assets
 0274                List<SceneObject> assets = scene.manifest.scene.assets.Values.ToList();
 275
 276                // Download the assets files
 0277                Dictionary<string, object> downloadedFiles = await DownloadAssetFiles(assets);
 278
 279                // Prepare scene.json
 0280                CatalystSceneEntityMetadata sceneJson = CreateSceneJson(scene, info);
 281
 282                // We apply the rotation of the scene so the entities are rotated
 0283                ApplyRotation(scene, info.rotation);
 284
 285                // Group all entities files
 0286                StatelessManifest statelessManifest = ManifestTranslator.WebBuilderSceneToStatelessManifest(scene.manife
 287
 288                // We undo the rotation of the scene
 0289                UndoRotationToScene(scene);
 290
 291                // This files are not encoded
 0292                Dictionary<string, object> entityFiles = new Dictionary<string, object>
 293                {
 294                    { BIWSettings.DEPLOYMENT_DEFINITION_FILE, statelessManifest },
 295                    { BIWSettings.DEPLOYMENT_SCENE_FILE, sceneJson },
 296                    { BIWSettings.DEPLOYMENT_ASSETS, assets },
 297                };
 298
 299                // This file will be encoded automatically
 0300                Dictionary<string, object> entityFilesToDecode = new Dictionary<string, object>
 301                {
 302                    { BIWSettings.DEPLOYMENT_SCENE_THUMBNAIL, thumbnail },
 303                };
 304
 0305                foreach (var downloadedFile in downloadedFiles)
 0306                    entityFilesToDecode.Add(downloadedFile.Key, downloadedFile.Value);
 307
 308                // Sent scene to kernel
 0309                StartPublishScene(scene, entityFilesToDecode, entityFiles, sceneJson, statelessManifest);
 0310            }
 0311            catch (Exception e)
 312            {
 313                // If there is a problem while are preparing the files we end the publishing with an error
 0314                PublishEnd(false, e.Message);
 0315            }
 0316        }
 317
 318        private void StartUnpublishScene(Dictionary<string, object > filesToDecode, Dictionary<string, object > files,St
 319        {
 0320            builderInWorldBridge.PublishScene(filesToDecode, files, metadata, statelessManifest, true);
 0321        }
 322
 323        private void StartPublishScene(IBuilderScene scene, Dictionary<string, object > filesToDecode, Dictionary<string
 324        {
 0325            startPublishingTimestamp = Time.realtimeSinceStartup;
 0326            BIWAnalytics.StartScenePublish(scene.scene.metricsCounter.currentCount);
 327
 328            // Note: if the aerialscreenshot is not available, this means that the scene has been deployed
 329            // from the panel instead of the editor, so we don't have the scene to rotate, we publish it to north direct
 0330            bool publishFromPanel = scene.aerialScreenshotTexture == null && scene.sceneType == IBuilderScene.SceneType.
 331
 0332            builderInWorldBridge.PublishScene(filesToDecode, files, metadata, statelessManifest, publishFromPanel);
 0333        }
 334
 335        private void PublishEnd(bool isOk, string message)
 336        {
 0337            if (type == TYPE.UNPUBLISH)
 338            {
 0339                PublishSceneResultPayload payload = new PublishSceneResultPayload();
 0340                payload.ok = isOk;
 0341                payload.error = message;
 0342                DataStore.i.builderInWorld.unpublishSceneResult.Set(payload);
 0343            }
 344            else
 345            {
 0346                if (isOk)
 347                {
 348                    // We notify the success of the deployment
 0349                    progressController.DeploySuccess();
 350
 351                    // Remove link to a land if exists
 0352                    builderSceneToDeploy.manifest.project.creation_coords = null;
 353
 354                    // Update project on the builder server
 0355                    context.builderAPIController.SetManifest(builderSceneToDeploy.manifest);
 0356                }
 357                else
 358                {
 0359                    progressController.DeployError(message);
 360                }
 0361                string successString = isOk ? "Success" : message;
 0362                BIWAnalytics.EndScenePublish(builderSceneToDeploy.scene.metricsCounter.currentCount, successString, Time
 363
 0364                if (isOk)
 0365                    builderSceneToDeploy = null;
 366
 0367                DataStore.i.builderInWorld.areShortcutsBlocked.Set(false);
 368
 0369                OnPublishFinish?.Invoke(isOk);
 370            }
 0371        }
 372
 373        internal CatalystSceneEntityMetadata CreateSceneJson(IBuilderScene builderScene, PublishInfo info)
 374        {
 0375            CatalystSceneEntityMetadata sceneJson = new CatalystSceneEntityMetadata();
 376
 377            //  Display info
 0378            sceneJson.display = new CatalystSceneEntityMetadata.Display();
 0379            sceneJson.display.title = builderScene.manifest.project.title;
 0380            sceneJson.display.description = builderScene.manifest.project.description;
 0381            sceneJson.display.navmapThumbnail = BIWSettings.DEPLOYMENT_SCENE_THUMBNAIL;
 382
 383            //  Contact
 0384            sceneJson.contact = new CatalystSceneEntityMetadata.Contact();
 0385            sceneJson.contact.name =  UserProfile.GetOwnUserProfile().name;
 386
 387            //  Tags
 0388            sceneJson.tags = Array.Empty<string>();
 389
 390            //  Spawn points
 0391            sceneJson.spawnPoints = Array.Empty<CatalystSceneEntityMetadata.SpawnPoint>();
 392
 393            //  Owner
 0394            sceneJson.owner = UserProfile.GetOwnUserProfile().ethAddress;
 395
 396            //  Scenes
 0397            sceneJson.scene = new CatalystSceneEntityMetadata.Scene();
 398
 399            //  Base Parcels
 0400            string baseParcels = info.coordsToPublish.x + "," + info.coordsToPublish.y;
 0401            sceneJson.scene.@base = baseParcels;
 402
 403            //  All parcels
 0404            string[] parcels = new string[builderScene.scene.sceneData.parcels.Length];
 0405            int cont = 0;
 406
 407            // Size
 0408            Vector2Int sceneSize = BIWUtils.GetSceneSize(builderScene.scene);
 0409            for (int x = 0; x < sceneSize.x; x++)
 410            {
 0411                for (int y = 0; y < sceneSize.y; y++)
 412                {
 0413                    parcels[cont] = (info.coordsToPublish.x + x) + "," + (info.coordsToPublish.y + y);
 0414                    cont++;
 415                }
 416            }
 417
 0418            sceneJson.scene.parcels = parcels;
 419
 420            //Main
 0421            sceneJson.main = BIWSettings.DEPLOYMENT_BUNDLED_GAME_FILE;
 422
 423            //Source
 0424            sceneJson.source = new CatalystSceneEntityMetadata.Source();
 0425            sceneJson.source.origin = BIWSettings.DEPLOYMENT_SOURCE_TYPE;
 0426            sceneJson.source.version = 1;
 0427            sceneJson.source.projectId = builderScene.manifest.project.id;
 0428            sceneJson.source.rotation = info.rotation.ToString().ToLowerInvariant();
 0429            sceneJson.source.layout = new CatalystSceneEntityMetadata.Source.Layout();
 0430            sceneJson.source.layout.rows = builderScene.manifest.project.rows;
 0431            sceneJson.source.layout.cols = builderScene.manifest.project.cols;
 0432            sceneJson.source.point = new CatalystSceneEntityMetadata.Vector2IntRepresentantion(info.coordsToPublish);
 433
 0434            return sceneJson;
 435        }
 436
 437        internal async UniTask<Dictionary<string, object>> DownloadAssetFiles(List<SceneObject> assetsToDownload)
 438        {
 0439            Dictionary<string, object> downloadedAssets = new Dictionary<string, object>();
 0440            List<WebRequestAsyncOperation> asyncOperations = new List<WebRequestAsyncOperation>();
 441
 0442            foreach (SceneObject sceneObject in assetsToDownload)
 443            {
 444                //We download each assets needed for the SceneObject
 0445                foreach (KeyValuePair<string, string> assetsContent in sceneObject.contents)
 446                {
 0447                    string url = sceneObject.GetBaseURL() + assetsContent.Value;
 0448                    var asyncOperation = Environment.i.platform.webRequest.Get(
 449                        url: url,
 450                        OnSuccess: (webRequestResult) =>
 451                        {
 0452                            byte[] byteArray = webRequestResult.GetResultData();
 453
 0454                            downloadedAssets.Add(BIWSettings.DEPLOYMENT_MODELS_FOLDER + "/" + assetsContent.Key, byteArr
 0455                        },
 0456                        OnFail: (webRequestResult) => { });
 0457                    asyncOperations.Add((WebRequestAsyncOperation)asyncOperation);
 458                }
 459            }
 460
 461            //We wait for all assets
 0462            foreach (WebRequestAsyncOperation operation in asyncOperations)
 463            {
 0464                await operation;
 465            }
 466
 0467            return downloadedAssets;
 0468        }
 469    }
 470}