using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using Robust.Shared.Map; using Robust.Shared.Utility; using YamlDotNet.Core; using YamlDotNet.RepresentationModel; namespace Robust.Server.Maps { internal static class YamlGridSerializer { public static YamlMappingNode SerializeGrid(IMapGrid mapGrid) { var grid = (IMapGridInternal) mapGrid; var gridn = new YamlMappingNode(); var info = new YamlMappingNode(); var chunkSeq = new YamlSequenceNode(); gridn.Add("settings", info); gridn.Add("chunks", chunkSeq); info.Add("chunksize", grid.ChunkSize.ToString(CultureInfo.InvariantCulture)); info.Add("tilesize", grid.TileSize.ToString(CultureInfo.InvariantCulture)); var chunks = grid.GetMapChunks(); foreach (var chunk in chunks) { var chunkNode = SerializeChunk(chunk.Value); chunkSeq.Add(chunkNode); } return gridn; } private static YamlNode SerializeChunk(MapChunk chunk) { var root = new YamlMappingNode(); var value = new YamlScalarNode($"{chunk.X},{chunk.Y}"); value.Style = ScalarStyle.DoubleQuoted; root.Add("ind", value); var gridNode = new YamlScalarNode(); root.Add("tiles", gridNode); gridNode.Value = SerializeTiles(chunk); return root; } private static string SerializeTiles(MapChunk chunk) { // number of bytes written per tile, because sizeof(Tile) is useless. const int structSize = 4; var nTiles = chunk.ChunkSize * chunk.ChunkSize * structSize; var barr = new byte[nTiles]; using (var stream = new MemoryStream(barr)) using (var writer = new BinaryWriter(stream)) { for (ushort y = 0; y < chunk.ChunkSize; y++) { for (ushort x = 0; x < chunk.ChunkSize; x++) { var tile = chunk.GetTile(x, y); writer.Write(tile.TypeId); writer.Write((byte)tile.Flags); writer.Write(tile.Variant); } } } return Convert.ToBase64String(barr); } public static void DeserializeChunk(IMapManager mapMan, IMapGridInternal grid, YamlMappingNode chunkData, IReadOnlyDictionary tileDefMapping, ITileDefinitionManager tileDefinitionManager) { var indNode = chunkData["ind"]; var tileNode = chunkData["tiles"]; var (chunkOffsetX, chunkOffsetY) = indNode.AsVector2i(); var tileBytes = Convert.FromBase64String(tileNode.ToString()); using var stream = new MemoryStream(tileBytes); using var reader = new BinaryReader(stream); mapMan.SuppressOnTileChanged = true; var chunk = grid.GetChunk(chunkOffsetX, chunkOffsetY); chunk.SuppressCollisionRegeneration = true; for (ushort y = 0; y < grid.ChunkSize; y++) { for (ushort x = 0; x < grid.ChunkSize; x++) { var id = reader.ReadUInt16(); var flags = (TileRenderFlag)reader.ReadByte(); var variant = reader.ReadByte(); var defName = tileDefMapping[id]; id = tileDefinitionManager[defName].TileId; var tile = new Tile(id, flags, variant); chunk.SetTile(x, y, tile); } } chunk.SuppressCollisionRegeneration = false; mapMan.SuppressOnTileChanged = false; } } }