< Summary

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

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
ManifestTranslator()0%2100%
SceneToStatelessManifest(...)0%20400%
TranslateSceneToManifest(...)0%2721600%
GetCleanUniqueName(...)0%12300%
TranslateManifestToScene(...)0%2721600%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/DCLPlugins/BuilderInWorld/Scripts/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 UnityEngine;
 12
 13namespace DCL.Builder
 14{
 15    public static class ManifestTranslator
 16    {
 17        private const string NFT_ETHEREUM_PROTOCOL = "ethereum://";
 18
 019        private static readonly Dictionary<string, int> idToHumanReadableDictionary = new Dictionary<string, int>()
 20        {
 21
 22            { "Transform", (int) CLASS_ID_COMPONENT.TRANSFORM },
 23
 24            { "GLTFShape", (int) CLASS_ID.GLTF_SHAPE },
 25
 26            { "NFTShape", (int) CLASS_ID.NFT_SHAPE },
 27
 28            { "Name", (int)CLASS_ID.NAME },
 29
 30            { "LockedOnEdit", (int)CLASS_ID.LOCKED_ON_EDIT },
 31
 32            { "VisibleOnEdit", (int)CLASS_ID.VISIBLE_ON_EDIT },
 33
 34            { "Script", (int) CLASS_ID_COMPONENT.SMART_ITEM }
 35        };
 36
 37        public static StatelessManifest SceneToStatelessManifest(ParcelScene scene)
 38        {
 039            StatelessManifest manifest = new StatelessManifest();
 040            manifest.schemaVersion = 1;
 41
 042            foreach (var entity in scene.entities.Values)
 43            {
 044                Entity statlesEntity = new Entity();
 045                statlesEntity.id = entity.entityId;
 46
 047                foreach (KeyValuePair<CLASS_ID_COMPONENT, IEntityComponent> entityComponent in entity.components)
 48                {
 049                    Component statelesComponent = new Component();
 050                    statelesComponent.type = idToHumanReadableDictionary.FirstOrDefault( x => x.Value == (int)entityComp
 051                    statelesComponent.value = entityComponent.Value.GetModel();
 052                    statlesEntity.components.Add(statelesComponent);
 53                }
 54
 055                foreach (KeyValuePair<Type, ISharedComponent> entitySharedComponent in entity.sharedComponents)
 56                {
 057                    Component statelesComponent = new Component();
 058                    statelesComponent.type = idToHumanReadableDictionary.FirstOrDefault( x => x.Value == (int)entityShar
 059                    statelesComponent.value = entitySharedComponent.Value.GetModel();
 060                    statlesEntity.components.Add(statelesComponent);
 61                }
 62
 063                manifest.entities.Add(statlesEntity);
 64            }
 65
 066            return manifest;
 67        }
 68
 69        public static WebBuilderScene TranslateSceneToManifest(ParcelScene scene)
 70        {
 071            WebBuilderScene builderScene = new WebBuilderScene();
 072            builderScene.id = Guid.NewGuid().ToString();
 73
 074            BuilderGround ground = new BuilderGround();
 075            List<string> namesList = new List<string>();
 76
 77            //We iterate all the entities to create its counterpart in the builder manifest
 078            foreach (IDCLEntity entity in scene.entities.Values)
 79            {
 080                BuilderEntity builderEntity = new BuilderEntity();
 081                builderEntity.id = entity.entityId;
 082                string componentType = "";
 083                string entityName = "";
 84
 85                // Iterate the entity components to transform them to the builder format
 086                foreach (KeyValuePair<CLASS_ID_COMPONENT, IEntityComponent> entityComponent in entity.components)
 87                {
 088                    BuilderComponent builderComponent = new BuilderComponent();
 089                    switch (entityComponent.Key)
 90                    {
 91                        case CLASS_ID_COMPONENT.TRANSFORM:
 092                            componentType = "Transform";
 93
 94                            // We can't serialize the quaternions from Unity since newton serializes have recursive prob
 095                            ProtocolV2.TransformComponent entityTransformComponentModel = new ProtocolV2.TransformCompon
 096                            entityTransformComponentModel.position = WorldStateUtils.ConvertUnityToScenePosition(entity.
 097                            entityTransformComponentModel.rotation = new ProtocolV2.QuaternionRepresentation(entity.game
 098                            entityTransformComponentModel.scale = entity.gameObject.transform.lossyScale;
 99
 0100                            builderComponent.data = entityTransformComponentModel;
 101
 0102                            break;
 103                        case CLASS_ID_COMPONENT.SMART_ITEM:
 0104                            componentType = "Script";
 105                            break;
 106                    }
 107
 108                    // We generate a new uuid for the component since there is no uuid for components in the stateful sc
 0109                    builderComponent.id = Guid.NewGuid().ToString();
 0110                    builderComponent.type = componentType;
 111
 112                    // Since the transform model data is different from the others, we set it in the switch instead of h
 0113                    if (builderComponent.type != "Transform")
 0114                        builderComponent.data = JsonConvert.SerializeObject(entityComponent.Value.GetModel());
 115
 0116                    builderEntity.components.Add(builderComponent.id);
 117
 0118                    if (!builderScene.components.ContainsKey(builderComponent.id))
 0119                        builderScene.components.Add(builderComponent.id, builderComponent);
 120                }
 121
 122                // Iterate the entity shared components to transform them to the builder format
 0123                foreach (KeyValuePair<System.Type, ISharedComponent> sharedEntityComponent in entity.sharedComponents)
 124                {
 0125                    BuilderComponent builderComponent = new BuilderComponent();
 126                    // We generate a new uuid for the component since there is no uuid for components in the stateful sc
 0127                    builderComponent.id = Guid.NewGuid().ToString();
 0128                    builderComponent.data = JsonConvert.SerializeObject(sharedEntityComponent.Value.GetModel());
 129
 0130                    if (sharedEntityComponent.Value is GLTFShape)
 131                    {
 0132                        componentType = "GLTFShape";
 133
 0134                        var gltfModel = JsonConvert.DeserializeObject<GLTFShape.Model>(builderComponent.data.ToString())
 135
 136                        //We get the associated asset to the GLFTShape and add it to the scene
 0137                        var asset = AssetCatalogBridge.i.sceneObjectCatalog.Get(gltfModel.assetId);
 0138                        if (!builderScene.assets.ContainsKey(asset.id))
 0139                            builderScene.assets.Add(asset.id, asset);
 140
 141                        // This is a special case. The builder needs the ground separated from the rest of the component
 142                        // Since all the grounds have the same asset, we assign it and disable the gizmos in the builder
 0143                        if (asset.category == BIWSettings.FLOOR_CATEGORY)
 144                        {
 0145                            ground.assetId = asset.id;
 0146                            ground.componentId = builderComponent.id;
 0147                            builderEntity.disableGizmos = true;
 148                        }
 149
 0150                        entityName = asset.name;
 0151                    }
 0152                    else if (sharedEntityComponent.Value is NFTShape)
 153                    {
 0154                        componentType = "NFTShape";
 155
 156                        // This is a special case where we are assigning the builder url field for NFTs because builder 
 157                        NFTShapeBuilderRepresentantion representantion;
 0158                        representantion.url = JsonConvert.DeserializeObject<NFTShape.Model>(builderComponent.data.ToStri
 0159                        builderComponent.data = JsonConvert.SerializeObject(representantion);
 160
 161                        //This is the name format that is used by builder, we will have a different name in unity due to
 0162                        entityName = "nft";
 0163                    }
 0164                    else if (sharedEntityComponent.Key == typeof(DCLName))
 165                    {
 0166                        componentType = "Name";
 0167                        entityName = ((DCLName.Model) sharedEntityComponent.Value.GetModel()).value;
 0168                    }
 0169                    else if (sharedEntityComponent.Key == typeof(DCLLockedOnEdit))
 170                    {
 0171                        componentType = "LockedOnEdit";
 172                    }
 173
 0174                    builderComponent.type = componentType;
 175
 0176                    builderEntity.components.Add(builderComponent.id);
 0177                    if (!builderScene.components.ContainsKey(builderComponent.id))
 0178                        builderScene.components.Add(builderComponent.id, builderComponent);
 179                }
 180
 181                // We need to give to each entity a unique name so we search for a unique name there
 182                // Also, since the name of the entity will be used in the code, we need to ensure that the it doesn't ha
 0183                builderEntity.name = GetCleanUniqueName(namesList, entityName);
 184
 0185                if (!builderScene.entities.ContainsKey(builderEntity.id))
 0186                    builderScene.entities.Add(builderEntity.id, builderEntity);
 187            }
 188
 189            //We add the limits to the scene, the current metrics are calculated in the builder
 0190            builderScene.limits = BIWUtils.GetSceneMetricsLimits(scene.parcels.Count);
 0191            builderScene.ground = ground;
 192
 0193            return builderScene;
 194        }
 195
 196        private static string GetCleanUniqueName(List<string> namesList, string currentName)
 197        {
 198            //We clean the name to don't include special characters
 0199            Regex r = new Regex("(?:[^a-z]|(?<=['\"])s)", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | Rege
 200
 0201            string newName = r.Replace(currentName, String.Empty);
 0202            newName = newName.ToLower();
 203
 204            //We get a unique name
 0205            bool uniqueName = false;
 0206            int cont = 2;
 0207            while (!uniqueName)
 208            {
 0209                if (!namesList.Contains(newName))
 0210                    uniqueName = true;
 211                else
 0212                    newName = newName + cont;
 213
 0214                cont++;
 215            }
 216
 0217            namesList.Add(newName);
 0218            return newName;
 219        }
 220
 221        public static ParcelScene TranslateManifestToScene(Manifest.Manifest manifest)
 222        {
 0223            GameObject parcelGameObject = new GameObject("Builder Scene SceneId: " + manifest.scene.id);
 0224            ParcelScene scene = parcelGameObject.AddComponent<ParcelScene>();
 225
 226            //We remove the old assets to they don't collide with the new ones
 0227            BIWUtils.RemoveAssetsFromCurrentScene();
 228
 229            //We add the assets from the scene to the catalog
 0230            var assets = manifest.scene.assets.Values.ToArray();
 0231            AssetCatalogBridge.i.AddScenesObjectToSceneCatalog(assets);
 232
 233            //We create and assign the data of the scene
 0234            LoadParcelScenesMessage.UnityParcelScene parcelData = new LoadParcelScenesMessage.UnityParcelScene();
 0235            parcelData.id = manifest.scene.id;
 236
 237            //We set the current scene in the 0,0
 0238            int x = 0;
 0239            int y = 0;
 240
 0241            parcelData.basePosition =  new Vector2Int(x, y);
 242
 243            //We set the parcels as the first one is in the base position, the first one will be in the bottom-left corn
 0244            parcelData.parcels =  new Vector2Int[manifest.project.rows * manifest.project.cols];
 245
 246            //We assign the parcels position
 0247            for (int index = 0; index == parcelData.parcels.Length; index++)
 248            {
 0249                parcelData.parcels[index] = new Vector2Int(x, y);
 0250                y++;
 0251                if (y == manifest.project.rows)
 252                {
 0253                    x++;
 0254                    y = CommonScriptableObjects.playerCoords.Get().y;
 255                }
 256            }
 257
 258            //We prepare the mappings to the scenes
 0259            Dictionary<string, string> contentDictionary = new Dictionary<string, string>();
 260
 0261            foreach (var sceneObject in assets)
 262            {
 0263                foreach (var content in sceneObject.contents)
 264                {
 0265                    if (!contentDictionary.ContainsKey(content.Key))
 0266                        contentDictionary.Add(content.Key, content.Value);
 267                }
 268            }
 269
 270            //We add the mappings to the scene
 0271            BIWUtils.AddSceneMappings(contentDictionary, BIWUrlUtils.GetUrlSceneObjectContent(), parcelData);
 272
 273            //The data is built so we set the data of the scene
 0274            scene.SetData(parcelData);
 275
 276            // We iterate all the entities to create the entity in the scene
 0277            foreach (BuilderEntity builderEntity in manifest.scene.entities.Values)
 278            {
 0279                var entity = scene.CreateEntity(builderEntity.id);
 280
 0281                bool nameComponentFound = false;
 282                // We iterate all the id of components in the entity, to add the component
 0283                foreach (string idComponent in builderEntity.components)
 284                {
 285                    //This shouldn't happen, the component should be always in the scene, but just in case
 0286                    if (!manifest.scene.components.ContainsKey(idComponent))
 287                        continue;
 288
 289                    // We get the component from the scene and create it in the entity
 0290                    BuilderComponent component = manifest.scene.components[idComponent];
 291
 0292                    switch (component.type)
 293                    {
 294                        case "Transform":
 0295                            DCLTransform.Model model = JsonConvert.DeserializeObject<DCLTransform.Model>(component.data.
 0296                            EntityComponentsUtils.AddTransformComponent(scene, entity, model);
 0297                            break;
 298
 299                        case "GLTFShape":
 0300                            LoadableShape.Model gltfModel = JsonConvert.DeserializeObject<LoadableShape.Model>(component
 0301                            EntityComponentsUtils.AddGLTFComponent(scene, entity, gltfModel, component.id);
 0302                            break;
 303
 304                        case "NFTShape":
 305                            //Builder use a different way to load the NFT so we convert it to our system
 0306                            string url = JsonConvert.DeserializeObject<string>(component.data.ToString());
 0307                            string assedId = url.Replace(NFT_ETHEREUM_PROTOCOL, "");
 0308                            int index = assedId.IndexOf("/", StringComparison.Ordinal);
 0309                            string partToremove = assedId.Substring(index);
 0310                            assedId = assedId.Replace(partToremove, "");
 311
 0312                            NFTShape.Model nftModel = new NFTShape.Model();
 0313                            nftModel.color = new Color(0.6404918f, 0.611472f, 0.8584906f);
 0314                            nftModel.src = url;
 0315                            nftModel.assetId = assedId;
 316
 0317                            EntityComponentsUtils.AddNFTShapeComponent(scene, entity, nftModel, component.id);
 0318                            break;
 319
 320                        case "Name":
 0321                            nameComponentFound = true;
 0322                            DCLName.Model nameModel = JsonConvert.DeserializeObject<DCLName.Model>(component.data.ToStri
 0323                            nameModel.builderValue = builderEntity.name;
 0324                            EntityComponentsUtils.AddNameComponent(scene , entity, nameModel, Guid.NewGuid().ToString())
 0325                            break;
 326
 327                        case "LockedOnEdit":
 0328                            DCLLockedOnEdit.Model lockedModel = JsonConvert.DeserializeObject<DCLLockedOnEdit.Model>(com
 0329                            EntityComponentsUtils.AddLockedOnEditComponent(scene , entity, lockedModel, Guid.NewGuid().T
 330                            break;
 331                    }
 332                }
 333
 334                // We need to mantain the builder name of the entity, so we create the equivalent part in biw. We do thi
 0335                if (!nameComponentFound)
 336                {
 0337                    DCLName.Model nameModel = new DCLName.Model();
 0338                    nameModel.value = builderEntity.name;
 0339                    nameModel.builderValue = builderEntity.name;
 0340                    EntityComponentsUtils.AddNameComponent(scene , entity, nameModel, Guid.NewGuid().ToString());
 341                }
 342            }
 343
 344            //We already have made all the necessary steps to configure the parcel, so we init the scene
 0345            scene.sceneLifecycleHandler.SetInitMessagesDone();
 346
 0347            return scene;
 348        }
 349
 350    }
 351}