fix(map): Fixes map diffs (Old Haven/Minax) (#720)
* Fixes reading map/static diffs.
This commit is contained in:
parent
0bcf7a8d01
commit
9729b5a7b0
8 changed files with 54 additions and 157 deletions
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)]
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue