Fix deserialization of empty grid chunks (#4565)

This commit is contained in:
Leon Friedrich
2023-11-13 05:22:20 +11:00
committed by GitHub
parent b3f0e467ee
commit 19564a421b
3 changed files with 48 additions and 22 deletions

View File

@@ -290,6 +290,9 @@ public sealed class MapLoaderSystem : EntitySystem
ReadGrids(data);
// grids prior to engine v175 might've been serialized with empty chunks which now throw debug asserts.
RemoveEmptyChunks(data);
// Then, go hierarchically in order and do the entity things.
StartupEntities(data);
@@ -305,6 +308,25 @@ public sealed class MapLoaderSystem : EntitySystem
return true;
}
private void RemoveEmptyChunks(MapData data)
{
var gridQuery = _serverEntityManager.GetEntityQuery<MapGridComponent>();
foreach (var uid in data.EntitiesToDeserialize.Keys)
{
if (!gridQuery.TryGetComponent(uid, out var gridComp))
continue;
foreach (var (index, chunk) in gridComp.Chunks)
{
if (chunk.FilledTiles > 0)
continue;
Log.Warning($"Encountered empty chunk while deserializing map. Grid: {ToPrettyString(uid)}. Chunk index: {index}");
gridComp.Chunks.Remove(index);
}
}
}
private bool VerifyEntitiesExist(MapData data, BeforeEntityReadEvent ev)
{
_stopwatch.Restart();

View File

@@ -12,6 +12,7 @@ using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Validation;
using Robust.Shared.Serialization.Markdown.Value;
using Robust.Shared.Serialization.TypeSerializers.Interfaces;
using Robust.Shared.Utility;
namespace Robust.Server.Maps;
@@ -93,6 +94,7 @@ internal sealed class MapChunkSerializer : ITypeSerializer<MapChunk, MappingData
IDependencyCollection dependencies, bool alwaysWrite = false,
ISerializationContext? context = null)
{
DebugTools.Assert(value.FilledTiles > 0, "Attempting to write an empty chunk");
var root = new MappingDataNode();
var ind = new ValueDataNode($"{value.X},{value.Y}");
root.Add("ind", ind);

View File

@@ -2,6 +2,7 @@ using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Robust.Shared.GameObjects;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
namespace Robust.Shared.Map.Enumerators;
@@ -26,33 +27,34 @@ public struct GridTileEnumerator
}
public bool MoveNext([NotNullWhen(true)] out TileRef? tileRef)
{
while (true)
{
while (true)
if (_index == _chunkSize * _chunkSize)
{
if (_index == _chunkSize * _chunkSize)
if (!_chunkEnumerator.MoveNext())
{
if (!_chunkEnumerator.MoveNext())
{
tileRef = null;
return false;
}
_index = 0;
tileRef = null;
return false;
}
var (chunkOrigin, chunk) = _chunkEnumerator.Current;
var x = (ushort) (_index / _chunkSize);
var y = (ushort) (_index % _chunkSize);
var tile = chunk.GetTile(x, y);
_index++;
if (_ignoreEmpty && tile.IsEmpty)
continue;
var gridX = x + chunkOrigin.X * _chunkSize;
var gridY = y + chunkOrigin.Y * _chunkSize;
tileRef = new TileRef(_gridUid, gridX, gridY, tile);
return true;
_index = 0;
}
var (chunkOrigin, chunk) = _chunkEnumerator.Current;
DebugTools.Assert(chunk.FilledTiles > 0, $"Encountered empty chunk while enumerating tiles");
var x = (ushort) (_index / _chunkSize);
var y = (ushort) (_index % _chunkSize);
var tile = chunk.GetTile(x, y);
_index++;
if (_ignoreEmpty && tile.IsEmpty)
continue;
var gridX = x + chunkOrigin.X * _chunkSize;
var gridY = y + chunkOrigin.Y * _chunkSize;
tileRef = new TileRef(_gridUid, gridX, gridY, tile);
return true;
}
}
}