Optimizations:

Use PLINQ for prototype loading. Most of the time is spent reading YAML so this should help a lot.
Don't regenerate collision for every tile placed by the map loader.
This commit is contained in:
Pieter-Jan Briers
2020-01-15 16:13:22 +01:00
parent 0739367013
commit 22cf53fd1c
8 changed files with 77 additions and 39 deletions

View File

@@ -103,42 +103,47 @@ namespace Robust.Server.Maps
gridId = grid.Index;
foreach (YamlMappingNode chunkNode in chunks.Cast<YamlMappingNode>())
foreach (var chunkNode in chunks.Cast<YamlMappingNode>())
{
DeserializeChunk(mapMan, grid, chunkNode, tileDefMapping, tileDefinitionManager);
}
}
private static void DeserializeChunk(IMapManager mapMan, IMapGrid grid, YamlMappingNode chunk, IReadOnlyDictionary<ushort, string> tileDefMapping, ITileDefinitionManager tileDefinitionManager)
private static void DeserializeChunk(IMapManager mapMan, IMapGridInternal grid, YamlMappingNode chunkData, IReadOnlyDictionary<ushort, string> tileDefMapping, ITileDefinitionManager tileDefinitionManager)
{
var indNode = chunk["ind"];
var tileNode = chunk["tiles"];
var indNode = chunkData["ind"];
var tileNode = chunkData["tiles"];
var (chunkOffsetX, chunkOffsetY) = indNode.AsVector2i() * grid.ChunkSize;
var (chunkOffsetX, chunkOffsetY) = indNode.AsVector2i();
var tileBytes = Convert.FromBase64String(tileNode.ToString());
using (var stream = new MemoryStream(tileBytes))
using (var reader = new BinaryReader(stream))
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++)
{
mapMan.SuppressOnTileChanged = true;
for (var y = 0; y < grid.ChunkSize; y++)
for (ushort x = 0; x < grid.ChunkSize; x++)
{
for (var x = 0; x < grid.ChunkSize; x++)
{
var id = reader.ReadUInt16();
var data = reader.ReadUInt16();
var id = reader.ReadUInt16();
var data = reader.ReadUInt16();
var defName = tileDefMapping[id];
id = tileDefinitionManager[defName].TileId;
var defName = tileDefMapping[id];
id = tileDefinitionManager[defName].TileId;
var tile = new Tile(id, data);
grid.SetTile(new MapIndices(chunkOffsetX + x, chunkOffsetY + y), tile);
}
var tile = new Tile(id, data);
chunk.SetTile(x, y, tile);
}
mapMan.SuppressOnTileChanged = false;
}
chunk.SuppressCollisionRegeneration = false;
chunk.RegenerateCollision();
mapMan.SuppressOnTileChanged = false;
}
}
}

View File

@@ -7,6 +7,10 @@ namespace Robust.Shared.Map
/// <inheritdoc />
internal interface IMapChunkInternal : IMapChunk
{
bool SuppressCollisionRegeneration { get; set; }
void RegenerateCollision();
/// <summary>
/// The last game simulation tick that this chunk was modified.
/// </summary>

View File

@@ -17,6 +17,6 @@ namespace Robust.Shared.Map
/// <param name="oldTile">The old tile that got replaced.</param>
void RaiseOnTileChanged(TileRef tileRef, Tile oldTile);
IMapGrid CreateGridNoEntity(MapId currentMapID, GridId? gridID = null, ushort chunkSize = 16, float snapSize = 1);
IMapGridInternal CreateGridNoEntity(MapId currentMapID, GridId? gridID = null, ushort chunkSize = 16, float snapSize = 1);
}
}

View File

@@ -125,7 +125,11 @@ namespace Robust.Shared.Map
LastModifiedTick = _grid.CurTick;
_tiles[xIndex, yIndex] = tile;
RegenerateCollision();
if (!SuppressCollisionRegeneration)
{
RegenerateCollision();
}
_grid.NotifyTileChanged(newTileRef, oldTile);
}
@@ -237,7 +241,9 @@ namespace Robust.Shared.Map
}
}
private void RegenerateCollision()
public bool SuppressCollisionRegeneration { get; set; }
public void RegenerateCollision()
{
// generate collision rects
GridChunkPartition.PartitionChunk(this, ref _colBoxes, out _cachedBounds);

View File

@@ -71,6 +71,8 @@ namespace Robust.Shared.Map
/// <inheritdoc />
public Box2 LocalBounds { get; private set; }
public bool SuppressCollisionRegeneration { get; set; }
/// <inheritdoc />
public ushort ChunkSize { get; }
@@ -268,6 +270,11 @@ namespace Robust.Shared.Map
#region ChunkAccess
public void RegenerateCollision()
{
throw new NotImplementedException();
}
/// <summary>
/// The total number of allocated chunks in the grid.
/// </summary>

View File

@@ -12,7 +12,7 @@ using Robust.Shared.Utility;
namespace Robust.Shared.Map
{
public partial class MapManager
internal partial class MapManager
{
#pragma warning disable 649
[Dependency] private readonly INetManager _netManager;

View File

@@ -16,7 +16,7 @@ using Robust.Shared.Utility;
namespace Robust.Shared.Map
{
/// <inheritdoc cref="IMapManager"/>
public partial class MapManager : IMapManagerInternal
internal partial class MapManager : IMapManagerInternal
{
#pragma warning disable 649
[Dependency] private readonly IGameTiming _gameTiming;
@@ -346,7 +346,7 @@ namespace Robust.Shared.Map
return CreateGridImpl(currentMapID, gridID, chunkSize, snapSize, true);
}
private IMapGrid CreateGridImpl(MapId currentMapID, GridId? gridID, ushort chunkSize, float snapSize, bool createEntity)
private IMapGridInternal CreateGridImpl(MapId currentMapID, GridId? gridID, ushort chunkSize, float snapSize, bool createEntity)
{
GridId actualID;
if (gridID != null)
@@ -418,7 +418,7 @@ namespace Robust.Shared.Map
return grid;
}
public IMapGrid CreateGridNoEntity(MapId currentMapID, GridId? gridID = null, ushort chunkSize = 16,
public IMapGridInternal CreateGridNoEntity(MapId currentMapID, GridId? gridID = null, ushort chunkSize = 16,
float snapSize = 1)
{
return CreateGridImpl(currentMapID, gridID, chunkSize, snapSize, false);

View File

@@ -203,23 +203,39 @@ namespace Robust.Shared.Prototypes
/// <inheritdoc />
public void LoadDirectory(ResourcePath path)
{
foreach (var filePath in _resources.ContentFindFiles(path))
{
if (filePath.Extension != "yml" || filePath.Filename.StartsWith("."))
{
continue;
}
using (var reader = new StreamReader(_resources.ContentFileRead(filePath), EncodingHelpers.UTF8))
_hasEverBeenReloaded = true;
var yamlStreams = _resources.ContentFindFiles(path).ToList().AsParallel()
.Where(filePath => filePath.Extension == "yml" && !filePath.Filename.StartsWith("."))
.Select(filePath =>
{
try
{
LoadFromStream(reader);
using var reader = new StreamReader(_resources.ContentFileRead(filePath), EncodingHelpers.UTF8);
var yamlStream = new YamlStream();
yamlStream.Load(reader);
return (yamlStream, filePath);
}
catch (Exception e)
when (e is YamlException || e is PrototypeLoadException)
catch (YamlException e)
{
Logger.ErrorS("eng", $"Exception whilst loading prototypes from {filePath}: {e}");
return (null, null);
}
})
.Where(p => p.yamlStream != null) // Filter out loading errors.
.ToList();
foreach (var (stream, filePath) in yamlStreams)
{
for (var i = 0; i < stream.Documents.Count; i++)
{
try
{
LoadFromDocument(stream.Documents[i]);
}
catch (Exception e)
{
Logger.ErrorS("eng", $"Exception whilst loading prototypes from {filePath}#{i}:\n{e}");
}
}
}