Ejemplo n.º 1
0
        public static MCMloRoomDef GetRoomForEntity(MCMloArchetypeDef mlo, Vector3[][] roomExtents, MCEntityDef entity)
        {
            for (int i = 0; i < roomExtents.Length; i++)
            {
                if (mlo.Rooms[i].Name == "limbo")
                {
                    continue;
                }

                var extents = roomExtents[i];
                var emin    = extents[0];
                var emax    = extents[1];

                var drawable = Program.GetDrawable(entity.ArchetypeName);

                if (drawable == null)
                {
                    if (
                        entity.Position.X >= emin.X && entity.Position.Y >= emin.Y && entity.Position.Z >= emin.Z &&
                        entity.Position.X <= emax.X && entity.Position.Y <= emax.Y && entity.Position.Z <= emax.Z
                        )
                    {
                        return(mlo.Rooms[i]);
                    }
                }
                else
                {
                    Quaternion orientation = new Quaternion(entity.Rotation);

                    Vector3 dcenter = (Vector3)drawable.BoundingCenter;
                    Vector3 dbbmin  = (Vector3)(Vector4)drawable.BoundingBoxMin - dcenter;
                    Vector3 dbbmax  = (Vector3)(Vector4)drawable.BoundingBoxMax - dcenter;
                    Vector3 center  = entity.Position + dcenter;

                    Vector3 bbmin = entity.Position + dbbmin;
                    Vector3 bbmax = entity.Position + dbbmax;

                    Vector3 c1 = Utils.RotateTransform(orientation, bbmin, entity.Position);
                    Vector3 c2 = Utils.RotateTransform(orientation, bbmax, entity.Position);

                    bbmin = Vector3.Min(c1, c2);
                    bbmax = Vector3.Max(c1, c2);

                    if (
                        center.X >= emin.X && center.Y >= emin.Y && center.Z >= emin.Z &&
                        center.X <= emax.X && center.Y <= emax.Y && center.Z <= emax.Z
                        )
                    {
                        return(mlo.Rooms[i]);
                    }
                }
            }

            return(null);
        }
Ejemplo n.º 2
0
        /* Specific Utils */
        public static void World2Mlo(MCEntityDef entity, MCMloArchetypeDef mlo, Vector3 mloWorldPosition, Quaternion mloWorldRotation)
        {
            var objRot       = new Quaternion(entity.Rotation.X, entity.Rotation.Y, entity.Rotation.Z, entity.Rotation.W);
            var rotationDiff = objRot * mloWorldRotation;    // Multiply initial entity rotation by mlo rotation

            rotationDiff.Normalize();

            entity.Position -= mloWorldPosition;                                                                          // Substract mlo world coords from entity world coords
            entity.Position  = Utils.RotateTransform(Quaternion.Invert(mloWorldRotation), entity.Position, Vector3.Zero); // Rotate entity around center of mlo instance (mlo entities rotations in space are inverted)

            entity.Rotation = new Vector4(rotationDiff.X, rotationDiff.Y, rotationDiff.Z, rotationDiff.W);
        }
Ejemplo n.º 3
0
        public static void Mlo2World(MCEntityDef entity, MCMloArchetypeDef mlo, Vector3 mloWorldPosition, Quaternion mloWorldRotation)
        {
            var objRot = new Quaternion(entity.Rotation.X, entity.Rotation.Y, entity.Rotation.Z, entity.Rotation.W);

            entity.Position  = Utils.RotateTransform(mloWorldRotation, entity.Position, Vector3.Zero);
            entity.Position += mloWorldPosition;

            var rotationDiff = objRot * Quaternion.Invert(mloWorldRotation);

            rotationDiff.Normalize();

            entity.Rotation = new Vector4(rotationDiff.X, rotationDiff.Y, rotationDiff.Z, rotationDiff.W);
        }
Ejemplo n.º 4
0
        static void HandleInjectEntitiesOptions(string[] args)
        {
            CommandLine.Parse <InjectEntitiesOptions>(args, (opts, gOpts) =>
            {
                if (opts.Ymap == null)
                {
                    Console.WriteLine("Please provide source ymap file with --ymap");
                    return;
                }

                if (opts.Ytyp == null)
                {
                    Console.WriteLine("Please provide source ytyp file with --ytyp");
                    return;
                }

                if (opts.Position == null || opts.Position.Count() != 3)
                {
                    Console.WriteLine("Please provide a correct position ex: --position 120.5,1370.312,769.2");
                    return;
                }

                if (opts.Rotation == null || opts.Rotation.Count() != 4)
                {
                    Console.WriteLine("Plase provide a correct rotation ex: --rotation 0,0,0,1");
                    return;
                }

                if (opts.Name == null)
                {
                    Console.WriteLine("Plase provide new generated ytyp name with --name");
                    return;
                }

                Init(args);

                var ymapInfos = Utils.Expand(opts.Ymap);
                var ymapNames = ymapInfos.Select(e => Path.GetFileNameWithoutExtension(e.Name)).ToArray();

                var position = new Vector3(opts.Position.ElementAt(0), opts.Position.ElementAt(1), opts.Position.ElementAt(2));
                var rotation = new Quaternion(opts.Rotation.ElementAt(0), opts.Rotation.ElementAt(1), opts.Rotation.ElementAt(2), opts.Rotation.ElementAt(3));

                var ytyp = new YtypFile();

                ytyp.Load(opts.Ytyp);

                MCMloArchetypeDef mlo = null;

                for (int i = 0; i < ytyp.CMapTypes.MloArchetypes.Count; i++)
                {
                    if (opts.MloName == null)
                    {
                        mlo = ytyp.CMapTypes.MloArchetypes[i];
                        break;
                    }
                    else
                    {
                        uint mloNameHash = Jenkins.Hash(opts.MloName.ToLowerInvariant());

                        if (mloNameHash == ytyp.CMapTypes.MloArchetypes[i].Name)
                        {
                            Console.Error.WriteLine("Found MLO => " + opts.MloName);
                            mlo = ytyp.CMapTypes.MloArchetypes[i];
                            break;
                        }
                    }
                }

                if (mlo == null)
                {
                    Console.WriteLine("MLO archetype not found");
                    return;
                }

                var ymaps = new List <YmapFile>();

                for (int i = 0; i < ymapInfos.Length; i++)
                {
                    var ymap = new YmapFile();

                    ymap.Load(ymapInfos[i].FullName);

                    ymaps.Add(ymap);
                }

                var missingYmap  = new YmapFile();
                int missingCount = 0;

                Console.WriteLine("Calculating rooms extents");

                var roomExtents = new Vector3[mlo.Rooms.Count][];

                for (int i = 0; i < mlo.Rooms.Count; i++)
                {
                    var room     = mlo.Rooms[i];
                    var entities = new List <MCEntityDef>();

                    for (int j = 0; j < room.AttachedObjects.Count; j++)
                    {
                        int idx = (int)room.AttachedObjects[j];

                        if (idx >= mlo.Entities.Count)
                        {
                            continue;
                        }

                        entities.Add(mlo.Entities[idx]);
                    }

                    var extents = Utils.CalcExtents(entities);

                    roomExtents[i] = extents[0];
                }

                for (int i = 0; i < ymaps.Count; i++)
                {
                    var ymap = ymaps[i];
                    var name = ymapNames[i];

                    if (name.StartsWith("portal_") || name.StartsWith("entityset_"))
                    {
                        continue;
                    }

                    var roomIdx           = mlo.Rooms.FindIndex(e => e.Name == name);
                    MCMloRoomDef currRoom = null;

                    if (roomIdx != -1)
                    {
                        currRoom = mlo.Rooms[roomIdx];
                    }

                    for (int j = 0; j < ymap.CMapData.Entities.Count; j++)
                    {
                        var entity           = ymap.CMapData.Entities[j];
                        var idx              = mlo.Entities.FindIndex(e => e.Guid == entity.Guid);
                        var room             = currRoom;
                        var originalPosition = entity.Position;
                        var originalRotation = entity.Rotation;

                        Console.WriteLine(name + " => " + j + " (" + idx + "|" + mlo.Entities.Count + ") => " + Utils.HashString((MetaName)entity.ArchetypeName));

                        Utils.World2Mlo(entity, mlo, position, rotation);

                        if (opts.Static && idx == -1)
                        {
                            if ((entity.Flags & 32) == 0)
                            {
                                Console.WriteLine("  Setting static flag (32)");
                                entity.Flags = entity.Flags | 32;
                            }
                        }

                        entity.LodLevel = Unk_1264241711.LODTYPES_DEPTH_ORPHANHD;

                        if (entity.Guid == 0)
                        {
                            var random = new Random();

                            do
                            {
                                entity.Guid = (uint)random.Next(1000000, Int32.MaxValue);
                            }while (mlo.Entities.Count(e => e.Guid == entity.Guid) > 0);

                            Console.WriteLine("  Setting random GUID => " + entity.Guid);
                        }

                        if (idx == -1)
                        {
                            idx = mlo.AddEntity(entity);
                        }
                        else
                        {
                            Console.WriteLine("  Found matching GUID => Overriding " + idx);
                            mlo.Entities[idx] = entity;
                        }


                        Console.WriteLine(j + " " + Utils.HashString((MetaName)entity.ArchetypeName));

                        if (room == null)
                        {
                            room = GetRoomForEntity(mlo, roomExtents, entity);
                        }

                        if (room == null)
                        {
                            entity.Position = originalPosition;
                            entity.Rotation = originalRotation;
                            entity.LodLevel = Unk_1264241711.LODTYPES_DEPTH_HD;

                            missingYmap.CMapData.Entities.Add(entity);

                            missingCount++;

                            continue;
                        }

                        uint id = (uint)idx;

                        if (room.AttachedObjects.IndexOf(id) == -1)
                        {
                            room.AttachedObjects.Add(id);
                        }

                        Console.WriteLine("  Room => " + room.Name);
                    }
                }

                if (opts.DeleteMissing)
                {
                    for (int i = mlo.Entities.Count - 1; i >= 0; i--)
                    {
                        bool found = false;

                        for (int j = 0; j < ymaps.Count; j++)
                        {
                            var ymap = ymaps[j];

                            if (ymap.CMapData.Entities.FindIndex(e => e.Guid == mlo.Entities[i].Guid) != -1)
                            {
                                found = true;
                                break;
                            }
                        }

                        if (!found)
                        {
                            Console.WriteLine("DELETE " + i);

                            for (int j = 0; j < mlo.Rooms.Count; j++)
                            {
                                for (int k = mlo.Rooms[j].AttachedObjects.Count - 1; k >= 0; k--)
                                {
                                    if (mlo.Rooms[j].AttachedObjects[k] == (uint)i)
                                    {
                                        mlo.Rooms[j].AttachedObjects.RemoveAt(k);
                                    }
                                }
                            }
                        }
                    }
                }

                var foundEntities = new Dictionary <uint, List <MCEntityDef> >();

                for (int i = 0; i < ymaps.Count; i++)
                {
                    var ymap = ymaps[i];
                    var name = ymapNames[i];

                    if (!name.StartsWith("entityset_"))
                    {
                        continue;
                    }

                    string[] split  = name.Split('_');
                    uint nameHash   = uint.Parse(split[1]);
                    string roomName = split[2];

                    if (!foundEntities.TryGetValue(nameHash, out List <MCEntityDef> fEntities))
                    {
                        fEntities = new List <MCEntityDef>();
                    }

                    int entitySetIdx = mlo.EntitySets.FindIndex(e => e.Name == nameHash);
                    int roomIdx      = mlo.Rooms.FindIndex(e => e.Name == roomName);

                    MCMloEntitySet currEntitySet = null;

                    if (entitySetIdx != -1)
                    {
                        currEntitySet = mlo.EntitySets[entitySetIdx];
                    }

                    for (int j = 0; j < ymap.CMapData.Entities.Count; j++)
                    {
                        var entity           = ymap.CMapData.Entities[j];
                        var idx              = currEntitySet.Entities.FindIndex(e => e.Guid == entity.Guid);
                        var entitySet        = currEntitySet;
                        var originalPosition = entity.Position;
                        var originalRotation = entity.Rotation;

                        Console.WriteLine(name + " => " + j + " (" + idx + "|" + currEntitySet.Entities.Count + ") => " + Utils.HashString((MetaName)entity.ArchetypeName));

                        Utils.World2Mlo(entity, mlo, position, rotation);

                        if (opts.Static && idx == -1)
                        {
                            if ((entity.Flags & 32) == 0)
                            {
                                Console.WriteLine("  Setting static flag (32)");
                                entity.Flags = entity.Flags | 32;
                            }
                        }

                        entity.LodLevel = Unk_1264241711.LODTYPES_DEPTH_ORPHANHD;

                        if (entity.Guid == 0)
                        {
                            var random = new Random();

                            do
                            {
                                entity.Guid = (uint)random.Next(1000000, Int32.MaxValue);
                            }while (currEntitySet.Entities.Count(e => e.Guid == entity.Guid) > 0);

                            Console.WriteLine("  Setting random GUID => " + entity.Guid);
                        }

                        if (idx == -1)
                        {
                            idx = currEntitySet.AddEntity(entity, roomIdx);
                        }
                        else
                        {
                            Console.WriteLine("  Found matching GUID => Overriding " + idx);
                            currEntitySet.Entities[idx] = entity;
                        }


                        Console.WriteLine(j + " " + Utils.HashString((MetaName)entity.ArchetypeName));

                        fEntities.Add(entity);
                    }

                    foundEntities[nameHash] = fEntities;
                }

                if (opts.DeleteMissing)
                {
                    foreach (var entry in foundEntities)
                    {
                        var entitySet = mlo.EntitySets.Find(e => e.Name == entry.Key);

                        for (int i = entitySet.Entities.Count - 1; i >= 0; i--)
                        {
                            bool found = false;

                            if (entry.Value.FindIndex(e => e.Guid == entitySet.Entities[i].Guid) != -1)
                            {
                                found = true;
                            }

                            if (!found)
                            {
                                Console.WriteLine("DELETE " + i);
                                entitySet.RemoveEntity(entitySet.Entities[i]);
                            }
                        }
                    }
                }

                ytyp.Save(opts.Name + ".ytyp");

                if (missingCount > 0)
                {
                    var extents = Utils.CalcExtents(missingYmap.CMapData.Entities);

                    missingYmap.CMapData.EntitiesExtentsMin  = extents[0][0];
                    missingYmap.CMapData.EntitiesExtentsMax  = extents[0][1];
                    missingYmap.CMapData.StreamingExtentsMin = extents[1][0];
                    missingYmap.CMapData.StreamingExtentsMax = extents[1][1];

                    missingYmap.Save(opts.Name + "_exterior.ymap");
                }
            });
        }
Ejemplo n.º 5
0
        static void HandleExtractEntitiesOptions(string[] args)
        {
            CommandLine.Parse <ExtractEntitiesOptions>(args, (opts, gOpts) =>
            {
                if (opts.Ytyp == null)
                {
                    Console.WriteLine("Please provide source ytyp file with --ytyp");
                    return;
                }

                if (opts.Position == null || opts.Position.Count() != 3)
                {
                    Console.WriteLine("Please provide a correct position ex: --position 120.5,1370.312,769.2");
                    return;
                }

                if (opts.Rotation == null || opts.Rotation.Count() != 4)
                {
                    Console.WriteLine("Plase provide a correct rotation ex: --rotation 0,0,0,1");
                    return;
                }

                if (opts.Name == null)
                {
                    Console.WriteLine("Plase output directory name with --name");
                    return;
                }

                Init(args);

                var position = new Vector3(opts.Position.ElementAt(0), opts.Position.ElementAt(1), opts.Position.ElementAt(2));
                var rotation = new Quaternion(opts.Rotation.ElementAt(0), opts.Rotation.ElementAt(1), opts.Rotation.ElementAt(2), opts.Rotation.ElementAt(3));

                var ytyp = new YtypFile();

                ytyp.Load(opts.Ytyp);

                if (!File.Exists(opts.Name + ".original.ytyp"))
                {
                    File.Copy(opts.Ytyp, opts.Name + ".original.ytyp");
                }

                MCMloArchetypeDef mlo = null;

                for (int i = 0; i < ytyp.CMapTypes.MloArchetypes.Count; i++)
                {
                    if (opts.MloName == null)
                    {
                        mlo = ytyp.CMapTypes.MloArchetypes[i];
                        break;
                    }
                    else
                    {
                        uint mloNameHash = Jenkins.Hash(opts.MloName.ToLowerInvariant());

                        if (mloNameHash == ytyp.CMapTypes.MloArchetypes[i].Name)
                        {
                            Console.Error.WriteLine("Found MLO => " + opts.MloName);
                            mlo = ytyp.CMapTypes.MloArchetypes[i];
                            break;
                        }
                    }
                }

                if (mlo == null)
                {
                    Console.WriteLine("MLO archetype not found");
                    return;
                }

                for (int roomId = 0; roomId < mlo.Rooms.Count; roomId++)
                {
                    var room         = mlo.Rooms[roomId];
                    var ymap         = new YmapFile();
                    var ymapEntities = new List <MCEntityDef>();

                    Console.WriteLine("Room => " + room.Name + " (" + room.AttachedObjects.Count + " entities)");

                    for (int i = 0; i < room.AttachedObjects.Count; i++)
                    {
                        int idx = (int)room.AttachedObjects[i];

                        if (idx >= mlo.Entities.Count)
                        {
                            continue;
                        }

                        var entity         = mlo.Entities[idx];
                        var entityRotation = new Quaternion(entity.Rotation.X, entity.Rotation.Y, entity.Rotation.Z, entity.Rotation.W);

                        Utils.Mlo2World(entity, mlo, position, rotation);

                        entity.LodLevel = Unk_1264241711.LODTYPES_DEPTH_HD;

                        if (entity.Guid == 0)
                        {
                            var random = new Random();

                            do
                            {
                                entity.Guid = (uint)random.Next(1000000, Int32.MaxValue);
                            }while (mlo.Entities.Count(e => e.Guid == entity.Guid) == 1);

                            Console.WriteLine("[" + i + "] Setting random GUID => " + entity.Guid);
                        }

                        ymapEntities.Add(entity);
                    }

                    ymap.CMapData.Entities = ymapEntities;

                    var extents = Utils.CalcExtents(ymap.CMapData.Entities);

                    ymap.CMapData.EntitiesExtentsMin  = extents[0][0];
                    ymap.CMapData.EntitiesExtentsMax  = extents[0][1];
                    ymap.CMapData.StreamingExtentsMin = extents[1][0];
                    ymap.CMapData.StreamingExtentsMax = extents[1][1];

                    Console.WriteLine(extents[0][0].X + " " + extents[0][0].Y + " " + extents[0][0].Z);
                    Console.WriteLine(extents[0][1].X + " " + extents[0][1].Y + " " + extents[0][1].Z);

                    Directory.CreateDirectory(opts.Name);

                    ymap.Save(opts.Name + "\\" + room.Name + ".ymap");
                }

                if (mlo.EntitySets != null)
                {
                    for (int i = 0; i < mlo.EntitySets.Count; i++)
                    {
                        var entitySet = mlo.EntitySets[i];

                        Directory.CreateDirectory(opts.Name + "\\entitysets\\" + entitySet.Name);

                        for (int roomId = 0; roomId < mlo.Rooms.Count; roomId++)
                        {
                            var room         = mlo.Rooms[roomId];
                            var ymap         = new YmapFile();
                            var ymapEntities = new List <MCEntityDef>();

                            Console.WriteLine("EntitySet => " + entitySet.Name + " [" + room.Name + "] (" + entitySet.Entities.Count + " entities)");

                            for (int j = 0; j < entitySet.Entities.Count; j++)
                            {
                                int targetRoom = (int)entitySet.Locations[j];

                                if (targetRoom != roomId)
                                {
                                    continue;
                                }

                                var entity         = entitySet.Entities[j];
                                var entityRotation = new Quaternion(entity.Rotation.X, entity.Rotation.Y, entity.Rotation.Z, entity.Rotation.W);

                                Utils.Mlo2World(entity, mlo, position, rotation);

                                entity.LodLevel = Unk_1264241711.LODTYPES_DEPTH_HD;

                                if (entity.Guid == 0)
                                {
                                    var random = new Random();

                                    do
                                    {
                                        entity.Guid = (uint)random.Next(1000000, Int32.MaxValue);
                                    }while (mlo.Entities.Count(e => e.Guid == entity.Guid) == 1);

                                    Console.WriteLine("[" + i + "] Setting random GUID => " + entity.Guid);
                                }

                                ymapEntities.Add(entity);
                            }

                            ymap.CMapData.Entities = ymapEntities;

                            var extents = Utils.CalcExtents(ymap.CMapData.Entities);

                            ymap.CMapData.EntitiesExtentsMin  = extents[0][0];
                            ymap.CMapData.EntitiesExtentsMax  = extents[0][1];
                            ymap.CMapData.StreamingExtentsMin = extents[1][0];
                            ymap.CMapData.StreamingExtentsMax = extents[1][1];

                            Console.WriteLine(extents[0][0].X + " " + extents[0][0].Y + " " + extents[0][0].Z);
                            Console.WriteLine(extents[0][1].X + " " + extents[0][1].Y + " " + extents[0][1].Z);

                            ymap.Save(opts.Name + "\\entitysets\\" + entitySet.Name + "\\entityset_" + entitySet.Name + "_" + room.Name + ".ymap");
                        }
                    }
                }

                /*
                 * for(int portalId=0; portalId < mlo.Portals.Count; portalId++)
                 * {
                 *  var portal = mlo.Portals[portalId];
                 *  var ymap = new YmapFile();
                 *  var ymapEntities = new List<MCEntityDef>();
                 *  var entitiesExtents = new List<Tuple<Vector3, Vector3>>();
                 *  var streamingExtents = new List<Tuple<Vector3, Vector3>>();
                 *
                 *  Console.WriteLine("Portal => " + portalId + " (" + portal.AttachedObjects.Count + " entities)");
                 *
                 *  for (int i = 0; i < portal.AttachedObjects.Count; i++)
                 *  {
                 *      int idx = (int)portal.AttachedObjects[i];
                 *
                 *      if (idx >= mlo.Entities.Count)
                 *          continue;
                 *
                 *      var entity = mlo.Entities[idx];
                 *      var entityRotation = new Quaternion(entity.Rotation.X, entity.Rotation.Y, entity.Rotation.Z, entity.Rotation.W);
                 *
                 *      Utils.Mlo2World(entity, mlo, position, rotation);
                 *
                 *      entity.LodLevel = Unk_1264241711.LODTYPES_DEPTH_HD;
                 *
                 *      if (entity.Guid == 0)
                 *      {
                 *          var random = new Random();
                 *
                 *          do
                 *          {
                 *              entity.Guid = (uint)random.Next(1000000, Int32.MaxValue);
                 *          }
                 *          while (mlo.Entities.Count(e => e.Guid == entity.Guid) == 1);
                 *
                 *          Console.WriteLine("[" + i + "] Setting random GUID => " + entity.Guid);
                 *      }
                 *
                 *      ymapEntities.Add(entity);
                 *  }
                 *
                 *  ymap.CMapData.Entities = ymapEntities;
                 *
                 *  var extents = Utils.CalcExtents(ymap.CMapData.Entities);
                 *
                 *  ymap.CMapData.EntitiesExtentsMin = extents[0][0];
                 *  ymap.CMapData.EntitiesExtentsMax = extents[0][1];
                 *  ymap.CMapData.StreamingExtentsMin = extents[1][0];
                 *  ymap.CMapData.StreamingExtentsMax = extents[1][1];
                 *
                 *  Console.WriteLine(extents[0][0].X + " " + extents[0][0].Y + " " + extents[0][0].Z);
                 *  Console.WriteLine(extents[0][1].X + " " + extents[0][1].Y + " " + extents[0][1].Z);
                 *
                 *  Directory.CreateDirectory(opts.Name);
                 *
                 *  ymap.Save(opts.Name + "\\portal_" + portalId.ToString().PadLeft(3, '0') + ".ymap");
                 *
                 *  var data = new JObject()
                 *  {
                 *      ["corners"] = new JArray()
                 *      {
                 *          new JObject() { ["x"] = portal.Corners[0][0], ["y"] = portal.Corners[0][1], ["z"] = portal.Corners[0][2] },
                 *          new JObject() { ["x"] = portal.Corners[1][0], ["y"] = portal.Corners[1][1], ["z"] = portal.Corners[1][2] },
                 *          new JObject() { ["x"] = portal.Corners[2][0], ["y"] = portal.Corners[2][1], ["z"] = portal.Corners[2][2] },
                 *          new JObject() { ["x"] = portal.Corners[3][0], ["y"] = portal.Corners[3][1], ["z"] = portal.Corners[3][2] },
                 *      },
                 *      ["flags"] = portal.Flags,
                 *      ["mirrorPriority"] = portal.MirrorPriority,
                 *      ["opacity"] = portal.Opacity,
                 *      ["roomFrom"] = portal.RoomFrom,
                 *      ["roomTo"] = portal.RoomTo,
                 *  };
                 *
                 *  var jsonString = JsonConvert.SerializeObject(data, new JsonSerializerSettings() { Formatting = Newtonsoft.Json.Formatting.Indented });
                 *
                 *  File.WriteAllText(opts.Name + "\\portal_" + portalId.ToString().PadLeft(3, '0') + ".json", jsonString);
                 * }
                 */
            });
        }