fix: Refactors getting static tiles to use enumerators (#1611)

### Summary
* Refactors getting static/multi tiles to not use allocations.
* `TileList` is now only used during bootstrapping and uses rented buffers to eliminate extra allocations.
* Replaces `StaticTile[] GetStaticTiles` with:
    ```cs
        Map.StaticTileEnumerable GetStaticTiles(int x, int y);
        Map.StaticTileEnumerable GetStaticAndMultiTiles(int x, int y);
        Map.StaticTileEnumerable GetMultiTiles(int x, int y);
    ```
* Removes `Synchronized` and `lock` from TileMatrix. It is no longer considered a multi-thread safe system.
This commit is contained in:
Kamron Batman 2023-11-26 09:39:46 -08:00 • committed by GitHub
parent 3b1637b2da
commit f21c9687b2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 359 additions and 512 deletions

View file

@ -15,9 +15,11 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using Server.Logging;
namespace Server;
@ -158,7 +160,6 @@ public class TileMatrix
public StaticTile[][][] EmptyStaticBlock => _emptyStaticBlock;
[MethodImpl(MethodImplOptions.Synchronized)]
public void SetStaticBlock(int x, int y, StaticTile[][][] value)
{
if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight)
@ -173,7 +174,6 @@ public class TileMatrix
_staticPatches[x][y >> 5] |= 1 << (y & 0x1F);
}
[MethodImpl(MethodImplOptions.Synchronized)]
public StaticTile[][][] GetStaticBlock(int x, int y)
{
if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight || DataStream == null || IndexStream == null)
@ -187,31 +187,28 @@ public class TileMatrix
if (tiles == null)
{
lock (_fileShare)
for (var i = 0; tiles == null && i < _fileShare.Count; ++i)
{
for (var i = 0; tiles == null && i < _fileShare.Count; ++i)
var shared = _fileShare[i];
lock (shared)
{
var shared = _fileShare[i];
lock (shared)
if (x < shared.BlockWidth && y < shared.BlockHeight)
{
if (x < shared.BlockWidth && y < shared.BlockHeight)
var theirTiles = shared._staticTiles[x];
if (theirTiles != null)
{
var theirTiles = shared._staticTiles[x];
tiles = theirTiles[y];
}
if (theirTiles != null)
if (tiles != null)
{
var theirBits = shared._staticPatches[x];
if (theirBits != null && (theirBits[y >> 5] & (1 << (y & 0x1F))) != 0)
{
tiles = theirTiles[y];
}
if (tiles != null)
{
var theirBits = shared._staticPatches[x];
if (theirBits != null && (theirBits[y >> 5] & (1 << (y & 0x1F))) != 0)
{
tiles = null;
}
tiles = null;
}
}
}
@ -226,44 +223,15 @@ public class TileMatrix
return tiles;
}
public StaticTile[] GetStaticTiles(int x, int y)
{
var tiles = GetStaticBlock(x >> 3, y >> 3);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Map.StaticTileEnumerable GetStaticTiles(int x, int y) => new(_map, new Point2D(x, y), includeMultis: false);
return tiles[x & 0x7][y & 0x7];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Map.StaticTileEnumerable GetStaticAndMultiTiles(int x, int y) => new(_map, new Point2D(x, y));
private readonly TileList m_TilesList = new();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Map.StaticTileEnumerable GetMultiTiles(int x, int y) => new(_map, new Point2D(x, y), false);
[MethodImpl(MethodImplOptions.Synchronized)]
public StaticTile[] GetStaticTiles(int x, int y, bool multis)
{
var tiles = GetStaticBlock(x >> 3, y >> 3);
if (!multis)
{
return tiles[x & 0x7][y & 0x7];
}
var any = false;
foreach (var multiTiles in _map.GetMultiTilesAt(x, y))
{
any = true;
m_TilesList.AddRange(multiTiles);
}
if (!any)
{
return tiles[x & 0x7][y & 0x7];
}
m_TilesList.AddRange(tiles[x & 0x7][y & 0x7]);
return m_TilesList.ToArray();
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void SetLandBlock(int x, int y, LandTile[] value)
{
if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight)
@ -278,7 +246,6 @@ public class TileMatrix
_landPatches[x][y >> 5] |= 1 << (y & 0x1F);
}
[MethodImpl(MethodImplOptions.Synchronized)]
public LandTile[] GetLandBlock(int x, int y)
{
if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight || MapStream == null)
@ -295,32 +262,26 @@ public class TileMatrix
return tiles;
}
lock (_fileShare)
for (var i = 0; tiles == null && i < _fileShare.Count; ++i)
{
for (var i = 0; tiles == null && i < _fileShare.Count; ++i)
var shared = _fileShare[i];
if (x < shared.BlockWidth && y < shared.BlockHeight)
{
var shared = _fileShare[i];
var theirTiles = shared._landTiles[x];
lock (shared)
if (theirTiles != null)
{
if (x < shared.BlockWidth && y < shared.BlockHeight)
tiles = theirTiles[y];
}
if (tiles != null)
{
var theirBits = shared._landPatches[x];
if (theirBits != null && (theirBits[y >> 5] & (1 << (y & 0x1F))) != 0)
{
var theirTiles = shared._landTiles[x];
if (theirTiles != null)
{
tiles = theirTiles[y];
}
if (tiles != null)
{
var theirBits = shared._landPatches[x];
if (theirBits != null && (theirBits[y >> 5] & (1 << (y & 0x1F))) != 0)
{
tiles = null;
}
}
tiles = null;
}
}
}
@ -344,7 +305,6 @@ public class TileMatrix
private StaticTile[] m_TileBuffer = new StaticTile[128];
[MethodImpl(MethodImplOptions.Synchronized)]
private unsafe StaticTile[][][] ReadStaticBlock(int x, int y)
{
try
@ -440,7 +400,6 @@ public class TileMatrix
throw new Exception("No assemblies were loaded, therefore we cannot load TileMatrix.");
}
[MethodImpl(MethodImplOptions.Synchronized)]
private unsafe LandTile[] ReadLandBlock(int x, int y)
{
try

View file

@ -15,7 +15,6 @@
using System;
using System.IO;
using System.Runtime.CompilerServices;
namespace Server;
@ -72,7 +71,6 @@ public class TileMatrixPatch
}
}
[MethodImpl(MethodImplOptions.Synchronized)]
private unsafe int PatchLand(TileMatrix matrix, string dataPath, string indexPath)
{
using var fsData = new FileStream(dataPath, FileMode.Open, FileAccess.Read, FileShare.Read);
@ -100,7 +98,6 @@ public class TileMatrixPatch
return count;
}
[MethodImpl(MethodImplOptions.Synchronized)]
private unsafe int PatchStatics(TileMatrix matrix, string dataPath, string indexPath, string lookupPath)
{
using var fsData = new FileStream(dataPath, FileMode.Open, FileAccess.Read, FileShare.Read);