fix(map): Fixes map diffs (Old Haven/Minax) (#720)

* Fixes reading map/static diffs.
This commit is contained in:
Kamron Batman 2021-08-22 23:35:18 -07:00 committed by GitHub
parent 0bcf7a8d01
commit 9729b5a7b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 54 additions and 157 deletions

View file

@ -6,16 +6,12 @@ namespace Server.Tests.Network
{ {
public class MapPatchesTests : IClassFixture<ServerFixture> public class MapPatchesTests : IClassFixture<ServerFixture>
{ {
[Theory] [Fact]
[InlineData(ProtocolChanges.Version500a, ClientFlags.Malas | ClientFlags.Trammel | ClientFlags.Felucca)] public void TestMapPatches()
[InlineData(ProtocolChanges.Version7090, ClientFlags.TerMur | ClientFlags.Trammel | ClientFlags.Felucca)]
public void TestMapPatches(ProtocolChanges protocolChanges, ClientFlags flags)
{ {
var ns = PacketTestUtilities.CreateTestNetState(); var ns = PacketTestUtilities.CreateTestNetState();
ns.ProtocolChanges = protocolChanges;
ns.Flags = flags;
var expected = ns.ProtocolChanges >= ProtocolChanges.Version6000 ? Span<byte>.Empty : new MapPatches().Compile(); var expected = new MapPatches().Compile();
ns.SendMapPatches(); ns.SendMapPatches();

View file

@ -254,7 +254,7 @@ namespace Server
if (string.IsNullOrWhiteSpace(input) || input.InsensitiveStartsWith("n")) if (string.IsNullOrWhiteSpace(input) || input.InsensitiveStartsWith("n"))
{ {
Utility.PushColor(ConsoleColor.Yellow); Utility.PushColor(ConsoleColor.Yellow);
Console.WriteLine("New Haven chosen with no map diffs."); Console.WriteLine("Client >= 6.0.0.0 chosen.");
Utility.PopColor(); Utility.PopColor();
return; return;
} }
@ -262,10 +262,9 @@ namespace Server
if (input.InsensitiveStartsWith("y")) if (input.InsensitiveStartsWith("y"))
{ {
SetSetting("maps.enablePre6000Trammel", true.ToString()); SetSetting("maps.enablePre6000Trammel", true.ToString());
SetSetting("maps.enableMapDiffPatches", true.ToString());
Utility.PushColor(ConsoleColor.Yellow); Utility.PushColor(ConsoleColor.Yellow);
Console.WriteLine("Old Haven chosen with map diffs."); Console.WriteLine("Client <= 5.0.9.1 chosen.");
Utility.PopColor(); Utility.PopColor();
return; return;
} }

View file

@ -47,9 +47,6 @@ namespace Server
[CallPriority(2)] [CallPriority(2)]
public static void Configure() public static void Configure()
{ {
// Set to true to support < 6.0.0 clients where map0.mul is both Felucca & Trammel
var pre6000Trammel = ServerConfiguration.GetOrUpdateSetting("maps.enablePre6000Trammel", false);
var failures = new List<string>(); var failures = new List<string>();
var count = 0; var count = 0;
@ -66,12 +63,6 @@ namespace Server
foreach (var def in maps) foreach (var def in maps)
{ {
if (def.Id == 1 && pre6000Trammel)
{
// Use Old Haven by changing file index to Felucca
def.FileIndex = 0;
}
try try
{ {
RegisterMap(def); RegisterMap(def);

View file

@ -11,25 +11,15 @@ namespace Server
static NativeReader() => m_NativeReader = Core.Unix ? new NativeReaderUnix() : new NativeReaderWin32(); static NativeReader() => m_NativeReader = Core.Unix ? new NativeReaderUnix() : new NativeReaderWin32();
public static unsafe int Read(FileStream source, void* buffer, int length) => public static unsafe int Read(FileStream source, void* buffer, int length) => Read(source, buffer, 0, length);
m_NativeReader.Read(source, buffer, length);
public static unsafe int Read(FileStream source, void* buffer, int bufferIndex, int length) => public static unsafe int Read(FileStream source, void* buffer, int bufferIndex, int length) =>
m_NativeReader.Read(source, buffer, bufferIndex, length); m_NativeReader.Read(source, buffer, bufferIndex, length);
public static unsafe int Read(FileStream source, int sourceIndex, void* buffer, int length) =>
m_NativeReader.Read(source, sourceIndex, buffer, length);
public static unsafe int Read(FileStream source, int sourceIndex, void* buffer, int bufferIndex, int length) =>
m_NativeReader.Read(source, sourceIndex, buffer, bufferIndex, length);
} }
public interface INativeReader public interface INativeReader
{ {
unsafe int Read(FileStream source, void* buffer, int length);
unsafe int Read(FileStream source, void* buffer, int bufferIndex, int length); unsafe int Read(FileStream source, void* buffer, int bufferIndex, int length);
unsafe int Read(FileStream source, int sourceIndex, void* buffer, int length);
unsafe int Read(FileStream source, int sourceIndex, void* buffer, int bufferIndex, int length);
} }
public sealed class NativeReaderWin32 : INativeReader public sealed class NativeReaderWin32 : INativeReader
@ -40,45 +30,18 @@ namespace Server
internal static extern unsafe bool ReadFile(IntPtr hFile, void* lpBuffer, uint nNumberOfBytesToRead, ref uint lpNumberOfBytesRead, NativeOverlapped* lpOverlapped); internal static extern unsafe bool ReadFile(IntPtr hFile, void* lpBuffer, uint nNumberOfBytesToRead, ref uint lpNumberOfBytesRead, NativeOverlapped* lpOverlapped);
} }
public unsafe int Read(FileStream source, void* buffer, int length) => InternalRead(source, buffer, 0, length);
public unsafe int Read(FileStream source, void* buffer, int bufferIndex, int length) => InternalRead(source, buffer, bufferIndex, length); public unsafe int Read(FileStream source, void* buffer, int bufferIndex, int length) => InternalRead(source, buffer, bufferIndex, length);
public unsafe int Read(FileStream source, int sourceIndex, void* buffer, int length) internal static unsafe int InternalRead(FileStream source, void* buffer, int bufferIndex, int length)
{
if (source.Seek(sourceIndex, SeekOrigin.Begin) == sourceIndex)
{
return InternalRead(source, buffer, 0, length);
}
return -1;
}
public unsafe int Read(FileStream source, int sourceIndex, void* buffer, int bufferIndex, int length)
{
if (source.Seek(sourceIndex, SeekOrigin.Begin) == sourceIndex)
{
return InternalRead(source, buffer, bufferIndex, length);
}
return -1;
}
internal unsafe int InternalRead(FileStream source, void* buffer, int bufferIndex, int length)
{ {
var byteCount = 0U; var byteCount = 0U;
if (!UnsafeNativeMethods.ReadFile(source.SafeFileHandle!.DangerousGetHandle(), (byte*)buffer + bufferIndex, (uint)length, ref byteCount, null)) if (UnsafeNativeMethods.ReadFile(source.SafeFileHandle!.DangerousGetHandle(), (byte*)buffer + bufferIndex, (uint)length, ref byteCount, null))
{ {
return -1; return (int)byteCount;
} }
if (byteCount > 0) return -1;
{
source.Seek(byteCount, SeekOrigin.Current);
}
return (int)byteCount;
} }
} }
@ -90,40 +53,10 @@ namespace Server
internal static extern unsafe int read(IntPtr ptr, void* buffer, int length); internal static extern unsafe int read(IntPtr ptr, void* buffer, int length);
} }
public unsafe int Read(FileStream source, void* buffer, int length) => InternalRead(source, buffer, 0, length); public unsafe int Read(FileStream source, void* buffer, int bufferIndex, int length) =>
InternalRead(source, buffer, bufferIndex, length);
public unsafe int Read(FileStream source, void* buffer, int bufferIndex, int length) => InternalRead(source, buffer, bufferIndex, length); internal unsafe int InternalRead(FileStream source, void* buffer, int bufferIndex, int length) =>
UnsafeNativeMethods.read(source.SafeFileHandle.DangerousGetHandle(), (byte*)buffer + bufferIndex, length);
public unsafe int Read(FileStream source, int sourceIndex, void* buffer, int length)
{
if (source.Seek(sourceIndex, SeekOrigin.Begin) == sourceIndex)
{
return InternalRead(source, buffer, 0, length);
}
return -1;
}
public unsafe int Read(FileStream source, int sourceIndex, void* buffer, int bufferIndex, int length)
{
if (source.Seek(sourceIndex, SeekOrigin.Begin) == sourceIndex)
{
return InternalRead(source, buffer, bufferIndex, length);
}
return -1;
}
internal unsafe int InternalRead(FileStream source, void* buffer, int bufferIndex, int length)
{
var byteCount = UnsafeNativeMethods.read(source.Handle, (byte*)buffer + bufferIndex, length);
if (byteCount > 0)
{
source.Seek(byteCount, SeekOrigin.Current);
}
return byteCount;
}
} }
} }

View file

@ -14,68 +14,39 @@
*************************************************************************/ *************************************************************************/
using System.Buffers; using System.Buffers;
using System.IO;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace Server.Network namespace Server.Network
{ {
public static class OutgoingMapPackets public static class OutgoingMapPackets
{ {
private static byte[] _mapPatchesPacket = new byte[41];
public static void SendMapPatches(this NetState ns) public static void SendMapPatches(this NetState ns)
{ {
if (ns == null || ns.ProtocolChanges >= ProtocolChanges.Version6000) if (ns == null)
{ {
return; return;
} }
int count; if (_mapPatchesPacket[0] == 0)
{
var writer = new SpanWriter(_mapPatchesPacket);
writer.Write((byte)0xBF); // Packet ID
writer.Write((ushort)41); // Length
writer.Write((ushort)0x18); // Subpacket
writer.Write(4);
if (ns.HasFlag(ClientFlags.TerMur)) for (int i = 0; i < 4; i++)
{ {
count = 6; var map = Map.Maps[i];
}
else if (ns.HasFlag(ClientFlags.Tokuno)) writer.Write(map.Tiles.Patch.StaticBlocks);
{ writer.Write(map.Tiles.Patch.LandBlocks);
count = 5; }
}
else if (ns.HasFlag(ClientFlags.Malas))
{
count = 4;
}
else if (ns.HasFlag(ClientFlags.Ilshenar))
{
count = 3;
}
else if (ns.HasFlag(ClientFlags.Trammel))
{
count = 2;
}
else if (ns.HasFlag(ClientFlags.Felucca))
{
count = 1;
}
else
{
return;
} }
var writer = new SpanWriter(stackalloc byte[9 + count * 8]); ns.Send(_mapPatchesPacket);
writer.Write((byte)0xBF); // Packet ID
writer.Seek(2, SeekOrigin.Current);
writer.Write((ushort)0x18); // Subpacket
writer.Write(count);
for (int i = 0; i < count; i++)
{
var map = Map.Maps[i];
writer.Write(map.Tiles.Patch.StaticBlocks);
writer.Write(map.Tiles.Patch.LandBlocks);
}
writer.WritePacketLength();
ns.Send(writer.Span);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]

View file

@ -262,7 +262,7 @@ namespace Server
Load(); Load();
} }
private unsafe static void Load() private static unsafe void Load()
{ {
var filePath = Core.FindDataFile("tiledata.mul"); var filePath = Core.FindDataFile("tiledata.mul");

View file

@ -31,6 +31,14 @@ namespace Server
public FileStream DataStream { get; } public FileStream DataStream { get; }
public BinaryReader IndexReader { get; } public BinaryReader IndexReader { get; }
private static bool Pre6000ClientSupport;
public static void Configure()
{
// Set to true to support < 6.0.0 clients where map0.mul is both Felucca & Trammel
Pre6000ClientSupport = ServerConfiguration.GetOrUpdateSetting("maps.enablePre6000Trammel", false);
}
public TileMatrix(Map owner, int fileIndex, int mapID, int width, int height) public TileMatrix(Map owner, int fileIndex, int mapID, int width, int height)
{ {
lock (_instances) lock (_instances)
@ -63,11 +71,13 @@ namespace Server
if (fileIndex != 0x7F) if (fileIndex != 0x7F)
{ {
fileIndex = Pre6000ClientSupport && mapID == 1 ? 0 : fileIndex;
var mapPath = Core.FindDataFile($"map{fileIndex}.mul", false); var mapPath = Core.FindDataFile($"map{fileIndex}.mul", false);
if (mapPath != null) if (mapPath != null)
{ {
MapStream = new FileStream(mapPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); MapStream = new FileStream(mapPath, FileMode.Open, FileAccess.Read, FileShare.Read);
} }
else else
{ {
@ -75,7 +85,7 @@ namespace Server
if (mapPath != null) if (mapPath != null)
{ {
MapStream = new FileStream(mapPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); MapStream = new FileStream(mapPath, FileMode.Open, FileAccess.Read, FileShare.Read);
_mapIndex = new UOPIndex(MapStream); _mapIndex = new UOPIndex(MapStream);
} }
else else
@ -88,7 +98,7 @@ namespace Server
if (indexPath != null) if (indexPath != null)
{ {
IndexStream = new FileStream(indexPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); IndexStream = new FileStream(indexPath, FileMode.Open, FileAccess.Read, FileShare.Read);
IndexReader = new BinaryReader(IndexStream); IndexReader = new BinaryReader(IndexStream);
} }
else else
@ -100,7 +110,7 @@ namespace Server
if (staticsPath != null) if (staticsPath != null)
{ {
DataStream = new FileStream(staticsPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); DataStream = new FileStream(staticsPath, FileMode.Open, FileAccess.Read, FileShare.Read);
} }
else else
{ {
@ -483,7 +493,7 @@ namespace Server
public int Height => 0; public int Height => 0;
public bool Ignored => m_ID == 2 || m_ID == 0x1DB || m_ID >= 0x1AE && m_ID <= 0x1B5; public bool Ignored => m_ID is 2 or 0x1DB or >= 0x1AE and <= 0x1B5;
public LandTile(short id, sbyte z) public LandTile(short id, sbyte z)
{ {

View file

@ -1,3 +1,4 @@
using System;
using System.IO; using System.IO;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -41,9 +42,8 @@ namespace Server
public static void Configure() public static void Configure()
{ {
// Using this requires the old mapDif files to be present. Only needed to support Clients < 6.0.0.0 PatchLandEnabled = ServerConfiguration.GetOrUpdateSetting("maps.enableMapDiffPatches", !Core.HS);
PatchLandEnabled = ServerConfiguration.GetOrUpdateSetting("maps.enableMapDiffPatches", false); PatchStaticsEnabled = ServerConfiguration.GetOrUpdateSetting("maps.enableStaticsDiffPatches", true);
PatchStaticsEnabled = ServerConfiguration.GetOrUpdateSetting("maps.enableStaticsDiffPatches", false);
} }
[MethodImpl(MethodImplOptions.Synchronized)] [MethodImpl(MethodImplOptions.Synchronized)]
@ -51,15 +51,14 @@ namespace Server
{ {
using var fsData = new FileStream(dataPath, FileMode.Open, FileAccess.Read, FileShare.Read); using var fsData = new FileStream(dataPath, FileMode.Open, FileAccess.Read, FileShare.Read);
using var fsIndex = new FileStream(indexPath, FileMode.Open, FileAccess.Read, FileShare.Read); using var fsIndex = new FileStream(indexPath, FileMode.Open, FileAccess.Read, FileShare.Read);
var indexReader = new BinaryReader(fsIndex); using var indexReader = new BinaryReader(fsIndex);
var count = (int)(indexReader.BaseStream.Length / 4); var count = (int)(indexReader.BaseStream.Length / 4);
for (var i = 0; i < count; ++i) for (var i = 0; i < count; i++)
{ {
var blockID = indexReader.ReadInt32(); var blockID = indexReader.ReadInt32();
var x = blockID / matrix.BlockHeight; var x = Math.DivRem(blockID, matrix.BlockHeight, out var y);
var y = blockID % matrix.BlockHeight;
fsData.Seek(4, SeekOrigin.Current); fsData.Seek(4, SeekOrigin.Current);
@ -73,8 +72,6 @@ namespace Server
matrix.SetLandBlock(x, y, tiles); matrix.SetLandBlock(x, y, tiles);
} }
indexReader.Close();
return count; return count;
} }