From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Sat, 11 Mar 2023 02:55:11 +0000 (+1100) Subject: Compress atmos serialization data (#14266) X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=1724ecb8d9300e03a6b4899c8f087f626be465c5;p=space-station-14.git Compress atmos serialization data (#14266) --- diff --git a/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs b/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs index c2f9cd0e0a..f0cbefa86b 100644 --- a/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs +++ b/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs @@ -1,9 +1,13 @@ -using Robust.Shared.Serialization; +using System.Globalization; +using Robust.Shared.Serialization; using Robust.Shared.Serialization.Manager; using Robust.Shared.Serialization.Markdown; using Robust.Shared.Serialization.Markdown.Mapping; using Robust.Shared.Serialization.Markdown.Validation; +using Robust.Shared.Serialization.Markdown.Value; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Generic; using Robust.Shared.Serialization.TypeSerializers.Interfaces; +using Robust.Shared.Utility; namespace Content.Server.Atmos.Serialization; @@ -20,21 +24,81 @@ public sealed class TileAtmosCollectionSerializer : ITypeSerializer>? instanceProvider = null) { - var data = serializationManager.Read(node, hookCtx, context); - var tiles = new Dictionary(); - if (data.TilesUniqueMixes != null) + node.TryGetValue(new ValueDataNode("version"), out var versionNode); + var version = ((ValueDataNode?) versionNode)?.AsInt() ?? 1; + Dictionary tiles; + + // Backwards compatability + if (version == 1) { - foreach (var (indices, mix) in data.TilesUniqueMixes) + var tile2 = node["tiles"]; + + var mixies = serializationManager.Read?>(tile2, hookCtx, context); + var unique = serializationManager.Read?>(node["uniqueMixes"], hookCtx, context); + + tiles = new Dictionary(); + + if (unique != null && mixies != null) { - try + foreach (var (indices, mix) in mixies) { - tiles.Add(indices, new TileAtmosphere(EntityUid.Invalid, indices, - data.UniqueMixes![mix].Clone())); + try + { + tiles.Add(indices, new TileAtmosphere(EntityUid.Invalid, indices, + unique[mix].Clone())); + } + catch (ArgumentOutOfRangeException) + { + Logger.Error( + $"Error during atmos serialization! Tile at {indices} points to an unique mix ({mix}) out of range!"); + } } - catch (ArgumentOutOfRangeException) + } + } + else + { + var dataNode = (MappingDataNode) node["data"]; + var tileNode = (MappingDataNode) dataNode["tiles"]; + var chunkSize = serializationManager.Read(dataNode["chunkSize"], hookCtx, context); + + var unique = serializationManager.Read?>(dataNode["uniqueMixes"], hookCtx, context); + + tiles = new Dictionary(); + + if (unique != null) + { + foreach (var (chunkNode, valueNode) in tileNode) { - Logger.Error( - $"Error during atmos serialization! Tile at {indices} points to an unique mix ({mix}) out of range!"); + var chunkOrigin = serializationManager.Read(chunkNode, hookCtx, context); + var chunk = serializationManager.Read(valueNode, hookCtx, context); + + foreach (var (mix, data) in chunk.Data) + { + for (var x = 0; x < chunkSize; x++) + { + for (var y = 0; y < chunkSize; y++) + { + var flag = data & (uint) (1 << (x + y * chunkSize)); + + if (flag == 0) + continue; + + var indices = new Vector2i(x + chunkOrigin.X * chunkSize, + y + chunkOrigin.Y * chunkSize); + + try + { + tiles.Add(indices, new TileAtmosphere(EntityUid.Invalid, indices, + unique[mix].Clone())); + } + catch (ArgumentOutOfRangeException) + { + Logger.Error( + $"Error during atmos serialization! Tile at {indices} points to an unique mix ({mix}) out of range!"); + } + } + } + } } } } @@ -46,41 +110,69 @@ public sealed class TileAtmosCollectionSerializer : ITypeSerializer(); - var uniqueMixHash = new Dictionary(); - var tiles = new Dictionary(); + var tileChunks = new Dictionary(); + var chunkSize = 4; - foreach (var (indices, tile) in value) + foreach (var (gridIndices, tile) in value) { if (tile.Air == null) continue; - if (uniqueMixHash.TryGetValue(tile.Air, out var index)) + var mixIndex = uniqueMixes.IndexOf(tile.Air); + + if (mixIndex == -1) { - tiles[indices] = index; - continue; + mixIndex = uniqueMixes.Count; + uniqueMixes.Add(tile.Air); } - uniqueMixes.Add(tile.Air); - var newIndex = uniqueMixes.Count - 1; - uniqueMixHash[tile.Air] = newIndex; - tiles[indices] = newIndex; + var chunkOrigin = SharedMapSystem.GetChunkIndices(gridIndices, chunkSize); + var tileChunk = tileChunks.GetOrNew(chunkOrigin); + var indices = SharedMapSystem.GetChunkRelative(gridIndices, chunkSize); + + var mixFlag = tileChunk.Data.GetOrNew(mixIndex); + mixFlag |= (uint) 1 << (indices.X + indices.Y * chunkSize); + tileChunk.Data[mixIndex] = mixFlag; } - if (uniqueMixes.Count == 0) uniqueMixes = null; - if (tiles.Count == 0) tiles = null; + if (uniqueMixes.Count == 0) + uniqueMixes = null; + if (tileChunks.Count == 0) + tileChunks = null; - return serializationManager.WriteValue(new TileAtmosData + var map = new MappingDataNode { - UniqueMixes = uniqueMixes, - TilesUniqueMixes = tiles - }, alwaysWrite, context); + { "version", 2.ToString(CultureInfo.InvariantCulture) }, + { + "data", serializationManager.WriteValue(new TileAtmosData + { + ChunkSize = chunkSize, + UniqueMixes = uniqueMixes, + TilesUniqueMixes = tileChunks, + }, alwaysWrite, context) + } + }; + + return map; } [DataDefinition] private struct TileAtmosData { + [DataField("chunkSize")] public int ChunkSize; + [DataField("uniqueMixes")] public List? UniqueMixes; - [DataField("tiles")] public Dictionary? TilesUniqueMixes; + [DataField("tiles")] public Dictionary? TilesUniqueMixes; + } + + [DataDefinition] + private record struct TileAtmosChunk() + { + /// + /// Key is unique mix and value is bitflag of the affected tiles. + /// + [IncludeDataField(customTypeSerializer: typeof(DictionarySerializer))] + public readonly Dictionary Data = new(); } public void CopyTo(ISerializationManager serializationManager, Dictionary source, ref Dictionary target, SerializationHookContext hookCtx,