< Summary

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

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
ManifestTranslator()0%2100%
StatelessToWebBuilderScene(...)0%90900%
WebBuilderSceneToStatelessManifest(...)0%42600%
ParcelSceneToStatelessManifest(...)0%56700%
ParcelSceneToWebBuilderScene(...)0%3421800%
GetWebBuilderRepresentationOfNFT(...)0%2100%
GetCleanUniqueName(...)0%12300%
ManifestToParcelSceneWithOnlyData(...)0%2100%
CreateSceneDataFromScene(...)0%42600%
ManifestToParcelScene(...)0%1321100%

File(s)

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

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using System.Text.RegularExpressions;
 5using DCL.Builder.Manifest;
 6using DCL.Components;
 7using DCL.Configuration;
 8using DCL.Controllers;
 9using DCL.Models;
 10using Newtonsoft.Json;
 11using Newtonsoft.Json.Linq;
 12using UnityEngine;
 13
 14namespace DCL.Builder
 15{
 16    public static class ManifestTranslator
 17    {
 018        private static readonly Dictionary<string, int> idToHumanReadableDictionary = new Dictionary<string, int>()
 19        {
 20            { "Transform", (int) CLASS_ID_COMPONENT.TRANSFORM },
 21
 22            { "GLTFShape", (int) CLASS_ID.GLTF_SHAPE },
 23
 24            { "NFTShape", (int) CLASS_ID.NFT_SHAPE },
 25
 26            { "Name", (int)CLASS_ID.NAME },
 27
 28            { "LockedOnEdit", (int)CLASS_ID.LOCKED_ON_EDIT },
 29
 30            { "VisibleOnEdit", (int)CLASS_ID.VISIBLE_ON_EDIT },
 31
 32            { "Script", (int) CLASS_ID_COMPONENT.SMART_ITEM }
 33        };
 34
 35        public static WebBuilderScene StatelessToWebBuilderScene(StatelessManifest manifest, Vector2Int parcelSize)
 36        {
 037            WebBuilderScene builderScene = new WebBuilderScene();
 038            builderScene.id = Guid.NewGuid().ToString();
 39
 040            BuilderGround ground = new BuilderGround();
 041            List<string> namesList = new List<string>();
 42            //We iterate all the entities to create its counterpart in the builder manifest
 043            foreach (Entity entity in manifest.entities)
 44            {
 045                BuilderEntity builderEntity = new BuilderEntity();
 046                builderEntity.id = entity.id;
 047                string entityName = builderEntity.id;
 48
 49                // Iterate the entity components to transform them to the builder format
 050                foreach (Component entityComponent in entity.components)
 51                {
 052                    BuilderComponent builderComponent = new BuilderComponent();
 053                    builderComponent.id = Guid.NewGuid().ToString();
 054                    builderComponent.type = entityComponent.type;
 055                    builderComponent.data = entityComponent.value;
 056                    builderEntity.components.Add(builderComponent.id);
 57
 058                    if (entityComponent.type == "NFTShape")
 59                    {
 060                        NFTShape.Model model = JsonConvert.DeserializeObject<NFTShape.Model>(entityComponent.value.ToStr
 061                        builderComponent.data = JsonConvert.SerializeObject(GetWebBuilderRepresentationOfNFT(model));
 62
 63                        //This is the name format that is used by builder, we will have a different name in unity due to
 064                        entityName = "nft";
 65                    }
 66
 067                    if (entityComponent.type ==  "GLTFShape")
 68                    {
 069                        var gltfModel = JsonConvert.DeserializeObject<GLTFShape.Model>(builderComponent.data.ToString())
 70
 71                        //We get the associated asset to the GLFTShape and add it to the scene
 072                        var asset = AssetCatalogBridge.i.sceneObjectCatalog.Get(gltfModel.assetId);
 073                        if (!builderScene.assets.ContainsKey(asset.id))
 074                            builderScene.assets.Add(asset.id, asset);
 75
 76                        //If the asset is a floor, we handle this situation for builder
 077                        if (asset.category == BIWSettings.FLOOR_CATEGORY)
 78                        {
 079                            ground.assetId = asset.id;
 080                            ground.componentId = builderComponent.id;
 081                            builderEntity.disableGizmos = true;
 82                        }
 83
 084                        entityName = asset.name;
 85                    }
 86
 087                    if (!builderScene.components.ContainsKey(builderComponent.id))
 088                        builderScene.components.Add(builderComponent.id, builderComponent);
 89                }
 90
 91                // We need to give to each entity a unique name so we search for a unique name there
 92                // Also, since the name of the entity will be used in the code, we need to ensure that the it doesn't ha
 093                builderEntity.name = GetCleanUniqueName(namesList, entityName);
 94
 095                if (!builderScene.entities.ContainsKey(builderEntity.id))
 096                    builderScene.entities.Add(builderEntity.id, builderEntity);
 97            }
 98
 99            //We add the limits to the scene, the current metrics are calculated in the builder
 0100            builderScene.limits = BIWUtils.GetSceneMetricsLimits(parcelSize.x + parcelSize.y);
 0101            builderScene.ground = ground;
 102
 0103            return builderScene;
 104        }
 105
 106        public static StatelessManifest WebBuilderSceneToStatelessManifest(WebBuilderScene scene)
 107        {
 0108            StatelessManifest manifest = new StatelessManifest();
 0109            manifest.schemaVersion = 1;
 110
 0111            foreach (var entity in scene.entities.Values)
 112            {
 0113                Entity statlesEntity = new Entity();
 0114                statlesEntity.id = entity.id;
 115
 0116                foreach (string componentId in entity.components)
 117                {
 0118                    foreach (BuilderComponent component in scene.components.Values)
 119                    {
 0120                        if(component.id != componentId)
 121                            continue;
 122
 0123                        Component statelesComponent = new Component();
 0124                        statelesComponent.type = component.type;
 125
 0126                        if (statelesComponent.type == "NFTShape")
 127                        {
 128                            string url;
 129                            try
 130                            {
 131                                // Builder use a different way to load the NFT so we convert it to our system
 0132                                url = ((NFTShapeBuilderRepresentantion) component.data).url;
 0133                            }
 0134                            catch (Exception e)
 135                            {
 136                                // Builder handles the components differently if they come from another site, if we can'
 0137                                JObject jObject = JObject.Parse(component.data.ToString());
 0138                                url = jObject["url"].ToString();
 0139                            }
 0140                            string assedId = url.Replace(BIWSettings.NFT_ETHEREUM_PROTOCOL, "");
 0141                            int index = assedId.IndexOf("/", StringComparison.Ordinal);
 0142                            string partToremove = assedId.Substring(index);
 0143                            assedId = assedId.Replace(partToremove, "");
 144
 145                            // We need to use this kind of representation because the color from unity is not serializab
 0146                            NFTShapeStatelessRepresentantion nftModel = new NFTShapeStatelessRepresentantion();
 0147                            nftModel.color = new NFTShapeStatelessRepresentantion.ColorRepresentantion(0.6404918f, 0.611
 0148                            nftModel.src = url;
 0149                            nftModel.assetId = assedId;
 150
 0151                            statelesComponent.value = nftModel;
 0152                        }
 153                        else
 154                        {
 0155                            statelesComponent.value = component.data;
 156                        }
 157
 0158                        statlesEntity.components.Add(statelesComponent);
 159                    }
 160                }
 161
 0162                manifest.entities.Add(statlesEntity);
 163            }
 164
 0165            return manifest;
 166        }
 167
 168        public static StatelessManifest ParcelSceneToStatelessManifest(IParcelScene scene)
 169        {
 0170            StatelessManifest manifest = new StatelessManifest();
 0171            manifest.schemaVersion = 1;
 172
 0173            foreach (var entity in scene.entities.Values)
 174            {
 0175                Entity statlesEntity = new Entity();
 0176                statlesEntity.id = entity.entityId.ToString();
 177
 0178                foreach (KeyValuePair<CLASS_ID_COMPONENT, IEntityComponent> entityComponent in scene.componentsManagerLe
 179                {
 0180                    Component statelesComponent = new Component();
 0181                    statelesComponent.type = idToHumanReadableDictionary.FirstOrDefault( x => x.Value == (int)entityComp
 182
 183                    // Transform component is handle a bit different due to quaternion serializations
 0184                    if (entityComponent.Key == CLASS_ID_COMPONENT.TRANSFORM)
 185                    {
 0186                        ProtocolV2.TransformComponent entityTransformComponentModel = new ProtocolV2.TransformComponent(
 0187                        entityTransformComponentModel.position = WorldStateUtils.ConvertUnityToScenePosition(entity.game
 0188                        entityTransformComponentModel.rotation = new ProtocolV2.QuaternionRepresentation(entity.gameObje
 0189                        entityTransformComponentModel.scale = entity.gameObject.transform.lossyScale;
 190
 0191                        statelesComponent.value = entityTransformComponentModel;
 0192                    }
 193                    else
 194                    {
 0195                        statelesComponent.value = entityComponent.Value.GetModel();
 196                    }
 197
 0198                    statlesEntity.components.Add(statelesComponent);
 199                }
 200
 0201                foreach (KeyValuePair<Type, ISharedComponent> entitySharedComponent in scene.componentsManagerLegacy.Get
 202                {
 0203                    Component statelesComponent = new Component();
 0204                    statelesComponent.type = idToHumanReadableDictionary.FirstOrDefault( x => x.Value == (int)entityShar
 0205                    statelesComponent.value = entitySharedComponent.Value.GetModel();
 0206                    statlesEntity.components.Add(statelesComponent);
 207                }
 208
 0209                manifest.entities.Add(statlesEntity);
 210            }
 211
 0212            return manifest;
 213        }
 214
 215        public static WebBuilderScene ParcelSceneToWebBuilderScene(ParcelScene scene)
 216        {
 0217            WebBuilderScene builderScene = new WebBuilderScene();
 0218            builderScene.id = Guid.NewGuid().ToString();
 219
 0220            BuilderGround ground = new BuilderGround();
 0221            List<string> namesList = new List<string>();
 222
 223            //We iterate all the entities to create its counterpart in the builder manifest
 0224            foreach (IDCLEntity entity in scene.entities.Values)
 225            {
 0226                BuilderEntity builderEntity = new BuilderEntity();
 0227                builderEntity.id = entity.entityId.ToString();
 0228                string componentType = "";
 0229                string entityName = "";
 230
 231                // Iterate the entity components to transform them to the builder format
 0232                foreach (KeyValuePair<CLASS_ID_COMPONENT, IEntityComponent> entityComponent in scene.componentsManagerLe
 233                {
 0234                    BuilderComponent builderComponent = new BuilderComponent();
 0235                    switch (entityComponent.Key)
 236                    {
 237                        case CLASS_ID_COMPONENT.TRANSFORM:
 0238                            componentType = "Transform";
 239
 240                            // We can't serialize the quaternions from Unity since newton serializes have recursive prob
 0241                            ProtocolV2.TransformComponent entityTransformComponentModel = new ProtocolV2.TransformCompon
 0242                            entityTransformComponentModel.position = WorldStateUtils.ConvertUnityToScenePosition(entity.
 0243                            entityTransformComponentModel.rotation = new ProtocolV2.QuaternionRepresentation(entity.game
 0244                            entityTransformComponentModel.scale = entity.gameObject.transform.lossyScale;
 245
 0246                            builderComponent.data = entityTransformComponentModel;
 247
 0248                            break;
 249                        case CLASS_ID_COMPONENT.SMART_ITEM:
 0250                            componentType = "Script";
 251                            break;
 252                    }
 253
 254                    // We generate a new uuid for the component since there is no uuid for components in the stateful sc
 0255                    builderComponent.id = Guid.NewGuid().ToString();
 0256                    builderComponent.type = componentType;
 257
 258                    // Since the transform model data is different from the others, we set it in the switch instead of h
 0259                    if (builderComponent.type != "Transform")
 0260                        builderComponent.data = entityComponent.Value.GetModel();
 261
 0262                    builderEntity.components.Add(builderComponent.id);
 263
 0264                    if (!builderScene.components.ContainsKey(builderComponent.id))
 0265                        builderScene.components.Add(builderComponent.id, builderComponent);
 266                }
 267
 268                // Iterate the entity shared components to transform them to the builder format
 0269                foreach (KeyValuePair<System.Type, ISharedComponent> sharedEntityComponent in scene.componentsManagerLeg
 270                {
 0271                    BuilderComponent builderComponent = new BuilderComponent();
 272                    // We generate a new uuid for the component since there is no uuid for components in the stateful sc
 0273                    builderComponent.id = Guid.NewGuid().ToString();
 0274                    builderComponent.data = sharedEntityComponent.Value.GetModel();
 275
 0276                    if (sharedEntityComponent.Value is GLTFShape)
 277                    {
 0278                        componentType = "GLTFShape";
 279
 0280                        var gltfModel = (GLTFShape.Model) builderComponent.data;
 281
 282                        //We get the associated asset to the GLFTShape and add it to the scene
 0283                        var asset = AssetCatalogBridge.i.sceneObjectCatalog.Get(gltfModel.assetId);
 0284                        if (!builderScene.assets.ContainsKey(asset.id))
 0285                            builderScene.assets.Add(asset.id, asset);
 286
 287                        // This is a special case. The builder needs the ground separated from the rest of the component
 288                        // Since all the grounds have the same asset, we assign it and disable the gizmos in the builder
 0289                        if (asset.category == BIWSettings.FLOOR_CATEGORY)
 290                        {
 0291                            ground.assetId = asset.id;
 0292                            ground.componentId = builderComponent.id;
 0293                            builderEntity.disableGizmos = true;
 294                        }
 295
 0296                        entityName = asset.name;
 0297                    }
 0298                    else if (sharedEntityComponent.Value is NFTShape)
 299                    {
 0300                        componentType = "NFTShape";
 301
 302                        // This is a special case where we are assigning the builder url field for NFTs because builder 
 0303                        NFTShape.Model model = (NFTShape.Model) builderComponent.data;
 0304                        builderComponent.data = GetWebBuilderRepresentationOfNFT(model);
 305
 306                        //This is the name format that is used by builder, we will have a different name in unity due to
 0307                        entityName = "nft";
 0308                    }
 0309                    else if (sharedEntityComponent.Key == typeof(DCLName))
 310                    {
 0311                        componentType = "Name";
 0312                        entityName = ((DCLName.Model) sharedEntityComponent.Value.GetModel()).value;
 0313                    }
 0314                    else if (sharedEntityComponent.Key == typeof(DCLLockedOnEdit))
 315                    {
 0316                        componentType = "LockedOnEdit";
 317                    }
 318
 0319                    builderComponent.type = componentType;
 320
 0321                    builderEntity.components.Add(builderComponent.id);
 0322                    if (!builderScene.components.ContainsKey(builderComponent.id))
 0323                        builderScene.components.Add(builderComponent.id, builderComponent);
 324                }
 325
 326                // We need to give to each entity a unique name so we search for a unique name there
 327                // Also, since the name of the entity will be used in the code, we need to ensure that the it doesn't ha
 0328                builderEntity.name = GetCleanUniqueName(namesList, entityName);
 329
 0330                if (!builderScene.entities.ContainsKey(builderEntity.id))
 0331                    builderScene.entities.Add(builderEntity.id, builderEntity);
 332            }
 333
 334            //We add the limits to the scene, the current metrics are calculated in the builder
 0335            builderScene.limits = BIWUtils.GetSceneMetricsLimits(scene.parcels.Count);
 0336            builderScene.metrics = new SceneMetricsModel();
 0337            builderScene.ground = ground;
 338
 0339            return builderScene;
 340        }
 341
 342        private static NFTShapeBuilderRepresentantion GetWebBuilderRepresentationOfNFT(NFTShape.Model model)
 343        {
 0344            NFTShapeBuilderRepresentantion representantion = new NFTShapeBuilderRepresentantion();
 0345            representantion.url = model.src;
 0346            return representantion;
 347        }
 348
 349        private static string GetCleanUniqueName(List<string> namesList, string currentName)
 350        {
 351            //We clean the name to don't include special characters
 0352            Regex r = new Regex("(?:[^a-z]|(?<=['\"])s)", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | Rege
 353
 0354            string newName = r.Replace(currentName, String.Empty);
 0355            newName = newName.ToLower();
 356
 357            //We get a unique name
 0358            bool uniqueName = false;
 0359            int cont = 2;
 0360            while (!uniqueName)
 361            {
 0362                if (!namesList.Contains(newName))
 0363                    uniqueName = true;
 364                else
 0365                    newName = newName + cont;
 366
 0367                cont++;
 368            }
 369
 0370            namesList.Add(newName);
 0371            return newName;
 372        }
 373
 374        public static IParcelScene ManifestToParcelSceneWithOnlyData(Manifest.Manifest manifest)
 375        {
 0376            GameObject parcelGameObject = new GameObject("Builder Scene SceneId: " + manifest.scene.id);
 0377            ParcelScene scene = parcelGameObject.AddComponent<ParcelScene>();
 378
 379            //We remove the old assets to they don't collide with the new ones
 0380            BIWUtils.RemoveAssetsFromCurrentScene();
 381
 382            //The data is built so we set the data of the scene
 0383            scene.SetData(CreateSceneDataFromScene(manifest));
 384
 0385            return scene;
 386        }
 387
 388        private static LoadParcelScenesMessage.UnityParcelScene CreateSceneDataFromScene(Manifest.Manifest manifest)
 389        {
 390            //We add the assets from the scene to the catalog
 0391            var assets = manifest.scene.assets.Values.ToArray();
 0392            AssetCatalogBridge.i.AddScenesObjectToSceneCatalog(assets);
 393
 394            //We create and assign the data of the scene
 0395            LoadParcelScenesMessage.UnityParcelScene parcelData = new LoadParcelScenesMessage.UnityParcelScene();
 0396            parcelData.id = manifest.scene.id;
 397
 398            //We set the current scene in the 0,0
 0399            int x = 0;
 0400            int y = 0;
 401
 0402            parcelData.basePosition =  new Vector2Int(x, y);
 403
 404            //We set the parcels as the first one is in the base position, the first one will be in the bottom-left corn
 0405            parcelData.parcels =  new Vector2Int[manifest.project.rows * manifest.project.cols];
 406
 407            //We assign the parcels position
 0408            for (int index = 0; index < parcelData.parcels.Length; index++)
 409            {
 0410                parcelData.parcels[index] = new Vector2Int(x, y);
 0411                x++;
 0412                if (x == manifest.project.rows)
 413                {
 0414                    y++;
 0415                    x = 0;
 416                }
 417            }
 418
 419            //We prepare the mappings to the scenes
 0420            Dictionary<string, string> contentDictionary = new Dictionary<string, string>();
 421
 0422            foreach (var sceneObject in assets)
 423            {
 0424                foreach (var content in sceneObject.contents)
 425                {
 0426                    if (!contentDictionary.ContainsKey(content.Key))
 0427                        contentDictionary.Add(content.Key, content.Value);
 428                }
 429            }
 430
 431            //We add the mappings to the scene
 0432            BIWUtils.AddSceneMappings(contentDictionary, BIWUrlUtils.GetUrlSceneObjectContent(), parcelData);
 433
 0434            return parcelData;
 435        }
 436
 437        public static IParcelScene ManifestToParcelScene(Manifest.Manifest manifest)
 438        {
 0439            GameObject parcelGameObject = new GameObject("Builder Scene SceneId: " + manifest.scene.id);
 0440            ParcelScene scene = parcelGameObject.AddComponent<ParcelScene>();
 441
 442            //We remove the old assets to they don't collide with the new ones
 0443            BIWUtils.RemoveAssetsFromCurrentScene();
 444
 445            //The data is built so we set the data of the scene
 0446            scene.SetData(CreateSceneDataFromScene(manifest));
 447
 448            // We iterate all the entities to create the entity in the scene
 0449            foreach (BuilderEntity builderEntity in manifest.scene.entities.Values)
 450            {
 0451                var entity = scene.CreateEntity(builderEntity.id.GetHashCode());
 452
 0453                bool nameComponentFound = false;
 454                // We iterate all the id of components in the entity, to add the component
 0455                foreach (string idComponent in builderEntity.components)
 456                {
 457                    //This shouldn't happen, the component should be always in the scene, but just in case
 0458                    if (!manifest.scene.components.ContainsKey(idComponent))
 459                        continue;
 460
 461                    // We get the component from the scene and create it in the entity
 0462                    BuilderComponent component = manifest.scene.components[idComponent];
 463
 0464                    switch (component.type)
 465                    {
 466                        case "Transform":
 0467                            DCLTransform.Model model = JsonConvert.DeserializeObject<DCLTransform.Model>(component.data.
 0468                            EntityComponentsUtils.AddTransformComponent(scene, entity, model);
 0469                            break;
 470
 471                        case "GLTFShape":
 0472                            LoadableShape.Model gltfModel = JsonConvert.DeserializeObject<LoadableShape.Model>(component
 0473                            EntityComponentsUtils.AddGLTFComponent(scene, entity, gltfModel, component.id);
 0474                            break;
 475
 476                        case "NFTShape":
 477                            //Builder use a different way to load the NFT so we convert it to our system
 0478                            string url = JsonConvert.DeserializeObject<string>(component.data.ToString());
 0479                            string assedId = url.Replace(BIWSettings.NFT_ETHEREUM_PROTOCOL, "");
 0480                            int index = assedId.IndexOf("/", StringComparison.Ordinal);
 0481                            string partToremove = assedId.Substring(index);
 0482                            assedId = assedId.Replace(partToremove, "");
 483
 0484                            NFTShape.Model nftModel = new NFTShape.Model();
 0485                            nftModel.color = new Color(0.6404918f, 0.611472f, 0.8584906f);
 0486                            nftModel.src = url;
 0487                            nftModel.assetId = assedId;
 488
 0489                            EntityComponentsUtils.AddNFTShapeComponent(scene, entity, nftModel, component.id);
 0490                            break;
 491
 492                        case "Name":
 0493                            nameComponentFound = true;
 0494                            DCLName.Model nameModel = JsonConvert.DeserializeObject<DCLName.Model>(component.data.ToStri
 0495                            nameModel.builderValue = builderEntity.name;
 0496                            EntityComponentsUtils.AddNameComponent(scene , entity, nameModel, Guid.NewGuid().ToString())
 0497                            break;
 498
 499                        case "LockedOnEdit":
 0500                            DCLLockedOnEdit.Model lockedModel = JsonConvert.DeserializeObject<DCLLockedOnEdit.Model>(com
 0501                            EntityComponentsUtils.AddLockedOnEditComponent(scene , entity, lockedModel, Guid.NewGuid().T
 502                            break;
 503                    }
 504                }
 505
 506                // We need to mantain the builder name of the entity, so we create the equivalent part in biw. We do thi
 0507                if (!nameComponentFound)
 508                {
 0509                    DCLName.Model nameModel = new DCLName.Model();
 0510                    nameModel.value = builderEntity.name;
 0511                    nameModel.builderValue = builderEntity.name;
 0512                    EntityComponentsUtils.AddNameComponent(scene , entity, nameModel, Guid.NewGuid().ToString());
 513                }
 514            }
 515
 516            //We already have made all the necessary steps to configure the parcel, so we init the scene
 0517            scene.sceneLifecycleHandler.SetInitMessagesDone();
 518
 0519            return scene;
 520        }
 521
 522    }
 523}