Use new BinaryData package to work on spans rather than streams.

This commit is contained in:
Ray Koopa 2019-01-18 20:44:02 +01:00
parent fcc2c74399
commit 7852ef9d5a
30 changed files with 421 additions and 715 deletions

View File

@ -0,0 +1,156 @@
using System.Collections.Generic;
using System.Drawing;
using System.Net;
using Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms;
namespace Syroot.Worms.Mgame.GameServer
{
internal partial class Client
{
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
public void HandleOWConnect(ConnectQuery packet)
{
SendPacket(new ConnectReply
{
Unknown = _server.Config.Name,
Unknown2 = _server.Config.Region,
Version = _server.Config.Version
});
}
public void HandleOWLogin(LoginQuery packet)
{
// Send login result.
// Create player infos from the given credentials. This would be the place to check for actual accounts.
LoginPlayerInfo[] playerInfos = new LoginPlayerInfo[packet.Logins.Length];
for (int i = 0; i < packet.Logins.Length; i++)
{
LoginCredentials credentials = packet.Logins[i];
playerInfos[i] = new LoginPlayerInfo { ID = credentials.ID, Rank = 19 };
}
SendPacket(new LoginReply
{
Result = LoginResult.Success,
PlayerInfos = playerInfos
});
// Send info text.
SendPacket(new ServerInfoReply
{
Text = "Welcome to the Online Worms Server."
});
// Send channels. The port is abused to identify the channel later on.
SendPacket(new ChannelInfosReply
{
Channels = new[]
{
new ChannelInfo
{
Name = "Test Channel",
EndPoint = new IPEndPoint(_server.Config.IPAddress, 1),
Type = ChannelType.Normal,
Color = Color.LightGreen,
Load = ChannelLoad.Highest
},
new ChannelInfo
{
Name = "Real Channel",
EndPoint = new IPEndPoint(_server.Config.IPAddress, 2),
Type = ChannelType.Normal
},
new ChannelInfo
{
Name = "Boredom Time",
EndPoint = new IPEndPoint(_server.Config.IPAddress, 3),
Type = ChannelType.Normal,
Load = ChannelLoad.Medium
},
new ChannelInfo
{
Name = "Nothing Goes",
EndPoint = new IPEndPoint(_server.Config.IPAddress, 4),
Type = ChannelType.Roping,
Color = Color.Orange,
Coins = 2,
Load = ChannelLoad.Closed
},
new ChannelInfo
{
Name = "Doper's Heaven",
EndPoint = new IPEndPoint(_server.Config.IPAddress, 5),
Type = ChannelType.Roping,
Color = Color.Orange,
Coins = 1,
Load = ChannelLoad.Full
},
new ChannelInfo
{
Name = "Unhelpful Channel",
EndPoint = new IPEndPoint(_server.Config.IPAddress, 6),
Type = ChannelType.Special
}
}
});
}
public void HandleOWChannelEnter(ChannelEnterQuery packet)
{
// Simply allow joining a channel running on the same server port.
SendPacket(new ChannelEnterReply
{
EndPoint = _server.Config.EndPoint
});
}
public void HandleOWChannelConnect(ChannelConnectQuery packet)
{
SendPacket(new ChannelConnectReply
{
Result = ChannelConnectResult.Success,
Player = new ChannelConnectPlayerInfo
{
ID = packet.Players[0].ID,
Name = "Your Name",
Experience = 1337,
Gold = 1000000,
Rank = 19,
GuildMarkIndex = 1,
GuildName = "Your Guild"
}
});
}
public void HandleOWChannelTop20(ChannelTop20Query packet)
{
// Send some simulated player rank infos.
ChannelTop20Reply reply = new ChannelTop20Reply
{
UnknownA = "Test",
Top20 = new List<ChannelTop20Player>(20)
};
for (int i = 0; i < 20; i++)
{
reply.Top20.Add(new ChannelTop20Player
{
Name = $"GoodPlayer{(char)('A' + i)}",
Rank = (ushort)((i + 6) / 3),
Experience = (ulong)(20 - i) * 957
});
}
SendPacket(reply);
// This is the last channel info packet, tell the client to go to the channel screen.
SendPacket(new ChannelEnterFinishReply());
}
public void HandleOWStartSingleGameQuery(StartSingleGameQuery packet)
{
SendPacket(new StartSingleGameReply
{
Success = packet.RoundType == GameStartRoundType.First
});
}
}
}

View File

@ -0,0 +1,14 @@
using Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua;
namespace Syroot.Worms.Mgame.GameServer
{
internal partial class Client
{
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
public void HandleWWPAConnect(ConnectQuery packet)
{
}
}
}

View File

@ -1,18 +1,14 @@
using System.Collections.Generic;
using System.Drawing;
using System.Net;
using System.Net.Sockets;
using System.Net.Sockets;
using System.Threading;
using Syroot.Worms.Mgame.GameServer.Core;
using Syroot.Worms.Mgame.GameServer.Packets;
using Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms;
namespace Syroot.Worms.Mgame.GameServer
{
/// <summary>
/// Represents a connection with an Online Worms client which replies to received packets appropriately.
/// </summary>
internal class Client : AppConnection
internal partial class Client : AppConnection
{
// ---- FIELDS -------------------------------------------------------------------------------------------------
@ -30,174 +26,13 @@ namespace Syroot.Worms.Mgame.GameServer
: base(tcpClient)
{
_server = server;
}
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
public void HandleConnect(ConnectQuery packet)
{
SendPacket(new ConnectReply
PrePacketHandle += (s, e) => _server.Log.Write(LogCategory.Client, FormatPacket(e, ">>"));
PrePacketSend += (s, e) =>
{
Unknown = _server.Config.Name,
Unknown2 = _server.Config.Region,
Version = _server.Config.Version
});
}
public void HandleLogin(LoginQuery packet)
{
// Send login result.
// Create player infos from the given credentials. This would be the place to check for actual accounts.
LoginPlayerInfo[] playerInfos = new LoginPlayerInfo[packet.Logins.Length];
for (int i = 0; i < packet.Logins.Length; i++)
{
LoginCredentials credentials = packet.Logins[i];
playerInfos[i] = new LoginPlayerInfo { ID = credentials.ID, Rank = 19 };
}
SendPacket(new LoginReply
{
Result = LoginResult.Success,
PlayerInfos = playerInfos
});
// Send info text.
SendPacket(new ServerInfoReply
{
Text = "Welcome to the Online Worms Server."
});
// Send channels. The port is abused to identify the channel later on.
SendPacket(new ChannelInfosReply
{
Channels = new[]
{
new ChannelInfo
{
Name = "Test Channel",
EndPoint = new IPEndPoint(_server.Config.IPAddress, 1),
Type = ChannelType.Normal,
Color = Color.LightGreen,
Load = ChannelLoad.Highest
},
new ChannelInfo
{
Name = "Real Channel",
EndPoint = new IPEndPoint(_server.Config.IPAddress, 2),
Type = ChannelType.Normal
},
new ChannelInfo
{
Name = "Boredom Time",
EndPoint = new IPEndPoint(_server.Config.IPAddress, 3),
Type = ChannelType.Normal,
Load = ChannelLoad.Medium
},
new ChannelInfo
{
Name = "Nothing Goes",
EndPoint = new IPEndPoint(_server.Config.IPAddress, 4),
Type = ChannelType.Roping,
Color = Color.Orange,
Coins = 2,
Load = ChannelLoad.Closed
},
new ChannelInfo
{
Name = "Doper's Heaven",
EndPoint = new IPEndPoint(_server.Config.IPAddress, 5),
Type = ChannelType.Roping,
Color = Color.Orange,
Coins = 1,
Load = ChannelLoad.Full
},
new ChannelInfo
{
Name = "Unhelpful Channel",
EndPoint = new IPEndPoint(_server.Config.IPAddress, 6),
Type = ChannelType.Special
}
}
});
}
public void HandleChannelEnter(ChannelEnterQuery packet)
{
// Simply allow joining a channel running on the same server port.
SendPacket(new ChannelEnterReply
{
EndPoint = _server.Config.EndPoint
});
}
public void HandleChannelConnect(ChannelConnectQuery packet)
{
SendPacket(new ChannelConnectReply
{
Result = ChannelConnectResult.Success,
Player = new ChannelConnectPlayerInfo
{
ID = packet.Players[0].ID,
Name = "Your Name",
Experience = 1337,
Gold = 1000000,
Rank = 19,
GuildMarkIndex = 1,
GuildName = "Your Guild"
}
});
}
public void HandleChannelTop20(ChannelTop20Query packet)
{
// Send some simulated player rank infos.
ChannelTop20Reply reply = new ChannelTop20Reply
{
UnknownA = "Test",
Top20 = new List<ChannelTop20Player>(20)
_server.Log.Write(LogCategory.Server, FormatPacket(e, "<<"));
if (_server.Config.SendDelay > 0)
Thread.Sleep(_server.Config.SendDelay);
};
for (int i = 0; i < 20; i++)
{
reply.Top20.Add(new ChannelTop20Player
{
Name = $"GoodPlayer{(char)('A' + i)}",
Rank = (ushort)((i + 6) / 3),
Experience = (ulong)(20 - i) * 957
});
}
SendPacket(reply);
// This is the last channel info packet, tell the client to go to the channel screen.
SendPacket(new ChannelEnterFinishReply());
}
public void HandleStartSingleGameQuery(StartSingleGameQuery packet)
{
SendPacket(new StartSingleGameReply
{
Success = packet.RoundType == GameStartRoundType.First
});
}
#if DEBUG
public void HandleRaw(RawPacket packet)
{
SendPacket(new RawPacket(PacketFormat.Wwpa, 0x0000,
new byte[] { 0x01, 0xC0, 0x01, 0x80, 0x00, 0x00, 0x00 }));
}
#endif
// ---- METHODS (PROTECTED) ------------------------------------------------------------------------------------
protected override void OnPrePacketHandle(Packet packet)
{
_server.Log.Write(LogCategory.Client, FormatPacket(packet, ">>"));
}
protected override void OnPrePacketSend(Packet packet)
{
_server.Log.Write(LogCategory.Server, FormatPacket(packet, "<<"));
if (_server.Config.SendDelay > 0)
Thread.Sleep(_server.Config.SendDelay);
}
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------

View File

@ -0,0 +1,26 @@
using System.Drawing;
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Core.IO
{
/// <summary>
/// Represents extension methods for <see cref="SpanWriter"/> instances.
/// </summary>
internal static class SpanWriterExtensions
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
/// <summary>
/// Writes the given <paramref name="color"/> as an RGB0 integer value.
/// </summary>
/// <param name="self">The extended instance.</param>
/// <param name="color">The <see cref="Color"/> to write.</param>
internal static void WriteColor(this SpanWriter self, Color color)
{
self.WriteByte(color.R);
self.WriteByte(color.G);
self.WriteByte(color.B);
self.WriteByte(0);
}
}
}

View File

@ -2,9 +2,9 @@
using System.IO;
using System.Net.Sockets;
using Syroot.BinaryData;
using Syroot.BinaryData.Memory;
using Syroot.Worms.Mgame.GameServer.Core.Net;
using Syroot.Worms.Mgame.GameServer.Core.Reflection;
using Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua;
namespace Syroot.Worms.Mgame.GameServer.Packets
{
@ -15,7 +15,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
{
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
private const int _maxDataSize = 2048;
private const int _maxDataSize = 1024;
private const ushort _owTagStartChannel = 0xFFFE;
private const ushort _owTagEndChannel = 0xFEFF;
private const ushort _wwpaTagStart = 0x2E9E;
@ -25,7 +25,6 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
private readonly MethodHandler<Packet> _methodHandler;
private readonly SafeNetworkStream _tcpStream;
private readonly PacketDataStream _packetDataStream;
private bool _disposed;
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
@ -40,9 +39,13 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
_methodHandler = new MethodHandler<Packet>(this);
TcpClient = tcpClient;
_tcpStream = TcpClient.GetSafeStream();
_packetDataStream = new PacketDataStream();
}
// ---- EVENTS -------------------------------------------------------------------------------------------------
protected event EventHandler<Packet> PrePacketHandle;
protected event EventHandler<Packet> PrePacketSend;
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
/// <summary>
@ -68,7 +71,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
Packet packet;
while ((packet = ReceivePacket()) != null)
{
OnPrePacketHandle(packet);
PrePacketHandle?.Invoke(this, packet);
_methodHandler.Handle(packet);
}
}
@ -80,41 +83,28 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
if (!_disposed)
{
if (disposing)
{
TcpClient.Dispose();
_packetDataStream.Dispose();
}
_disposed = true;
}
}
protected virtual void OnPrePacketHandle(Packet packet) { }
protected virtual void OnPrePacketSend(Packet packet) { }
protected bool SendPacket(Packet packet)
{
OnPrePacketSend(packet);
// Serialize the packet data to retrieve its size.
_packetDataStream.Position = 0;
packet.SaveData(_packetDataStream);
// Send the total packet data including head and tail.
PrePacketSend?.Invoke(this, packet);
try
{
// Handle specific packet formats.
PacketAttribute attribute = PacketFactory.GetAttribute(packet);
switch (attribute.Format)
{
case PacketFormat.OWChannel:
SendOWChannelPacket(attribute.ID);
SendOWChannelPacket(attribute.ID, packet);
break;
case PacketFormat.OWServer:
SendOWServerPacket(attribute.ID);
SendOWServerPacket(attribute.ID, packet);
break;
case PacketFormat.Wwpa:
SaveWwpaPacket(packet);
SaveWwpaPacket(attribute.ID, packet);
break;
default:
throw new IOException("Cannot send unknown packet format.");
@ -155,7 +145,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
int dataSize = _tcpStream.ReadUInt16();
int id = _tcpStream.Read1Byte();
// Read data.
byte[] data = _tcpStream.ReadBytes(dataSize);
SpanReader reader = new SpanReader(_tcpStream.ReadBytes(dataSize), encoding: Encodings.Win949);
// Read tail.
ushort endTag = _tcpStream.ReadUInt16();
if (endTag != _owTagEndChannel)
@ -163,8 +153,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
// Instantiate, deserialize, and return packet.
Packet packet = PacketFactory.Create(PacketFormat.OWChannel, id);
using (PacketDataStream stream = new PacketDataStream(data))
packet.LoadData(stream);
packet.LoadData(reader);
return packet;
}
@ -173,12 +162,11 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
// Read head.
int dataSize = _tcpStream.ReadUInt16();
// Read data.
byte[] data = _tcpStream.ReadBytes(dataSize);
SpanReader reader = new SpanReader(_tcpStream.ReadBytes(dataSize), encoding: Encodings.Win949);
// Instantiate, deserialize, and return packet.
Packet packet = PacketFactory.Create(PacketFormat.OWServer, tag);
using (PacketDataStream stream = new PacketDataStream(data))
packet.LoadData(stream);
packet.LoadData(reader);
return packet;
}
@ -203,59 +191,60 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
throw new PacketException("Invalid WWPA packet end tag.");
// Instantiate, deserialize, and return packet.
int id = 0;
SpanReader reader = new SpanReader(PacketCompression.Decompress(compressedData), encoding: Encodings.Win949);
int id = reader.ReadInt32();
Packet packet = PacketFactory.Create(PacketFormat.Wwpa, id);
ReadOnlySpan<byte> decompressedData = PacketCompression.Decompress(compressedData);
using (PacketDataStream stream = new PacketDataStream(decompressedData.ToArray()))
packet.LoadData(stream);
packet.LoadData(reader.Slice());
return packet;
}
private void SendOWChannelPacket(int id)
private void SendOWChannelPacket(int id, Packet packet)
{
// Retrieve data size. Must have at least 1 byte.
if (_packetDataStream.Position == 0)
_packetDataStream.WriteByte(0);
ushort dataSize = (ushort)_packetDataStream.Position;
// Retrieve data. Must have at least 1 byte.
SpanWriter writer = new SpanWriter(new byte[_maxDataSize], encoding: Encodings.Win949);
packet.SaveData(writer);
writer.Position = Math.Max(1, writer.Position);
// Send head.
_tcpStream.WriteUInt16(_owTagStartChannel);
_tcpStream.WriteByte(1);
_tcpStream.WriteUInt16(dataSize);
_tcpStream.WriteUInt16((ushort)writer.Position);
_tcpStream.WriteByte((byte)id);
// Send data.
_tcpStream.Write(_packetDataStream.GetSpan());
_tcpStream.Write(writer.Span);
// Send tail.
_tcpStream.WriteUInt16(_owTagEndChannel);
}
private void SendOWServerPacket(int id)
private void SendOWServerPacket(int id, Packet packet)
{
// Retrieve data size.
ushort dataSize = (ushort)_packetDataStream.Position;
// Retrieve data.
SpanWriter writer = new SpanWriter(new byte[_maxDataSize], encoding: Encodings.Win949);
packet.SaveData(writer);
// Send head.
_tcpStream.WriteUInt16((ushort)id);
_tcpStream.WriteUInt16(dataSize);
_tcpStream.WriteUInt16((ushort)writer.Position);
// Write data.
_tcpStream.Write(_packetDataStream.GetSpan());
_tcpStream.Write(writer.Span);
}
private void SaveWwpaPacket(Packet packet)
private void SaveWwpaPacket(int id, Packet packet)
{
// Retrieve (decompressed) data size.
ReadOnlySpan<byte> decompressedData = _packetDataStream.GetSpan();
ReadOnlySpan<byte> compressedData = PacketCompression.Compress(decompressedData);
SpanWriter writer = new SpanWriter(new byte[_maxDataSize], encoding: Encodings.Win949);
packet.SaveData(writer);
ReadOnlySpan<byte> compressedData = PacketCompression.Compress(writer.Span);
// Send head.
_tcpStream.WriteUInt16(_wwpaTagStart);
_tcpStream.WriteBoolean(true);
_tcpStream.WriteBoolean(false);
_tcpStream.WriteBoolean(true); // isCompressed
_tcpStream.WriteUInt16((ushort)decompressedData.Length);
_tcpStream.WriteUInt16((ushort)writer.Span.Length);
_tcpStream.WriteUInt32((uint)compressedData.Length);
_tcpStream.WriteInt32(1); // Apparently only needs to be same as in tail.

View File

@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Net;
using Syroot.BinaryData;
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
{
@ -25,33 +25,33 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(PacketDataStream stream)
internal override void LoadData(SpanReader reader)
{
Players = new List<ChannelConnectPlayerCredentials>
{
new ChannelConnectPlayerCredentials
{
ID = stream.ReadString(12),
Password = stream.ReadString(12)
ID = reader.ReadStringFix(12),
Password = reader.ReadStringFix(12)
}
};
ClientIP = IPAddress.Parse(stream.ReadString(15));
ClientVersion = stream.ReadUInt16();
UnknownA = stream.ReadUInt16();
ClientIP = IPAddress.Parse(reader.ReadStringFix(15));
ClientVersion = reader.ReadUInt16();
UnknownA = reader.ReadUInt16();
ushort additionalPlayers = stream.ReadUInt16();
ushort additionalPlayers = reader.ReadUInt16();
for (int i = 0; i < additionalPlayers; i++)
{
Players.Add(new ChannelConnectPlayerCredentials
{
ID = stream.ReadString(12),
Password = stream.ReadString(12)
ID = reader.ReadStringFix(12),
Password = reader.ReadStringFix(12)
});
}
UnknownB = stream.Read1Byte();
UnknownB = reader.ReadByte();
}
internal override void SaveData(PacketDataStream stream) => throw new NotImplementedException();
internal override void SaveData(SpanWriter writer) => throw new NotImplementedException();
}
internal class ChannelConnectPlayerCredentials

View File

@ -1,6 +1,5 @@
using System;
using Syroot.BinaryData;
using Syroot.Worms.Core.IO;
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
{
@ -18,55 +17,55 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(PacketDataStream stream) => throw new NotImplementedException();
internal override void LoadData(SpanReader reader) => throw new NotImplementedException();
internal override void SaveData(PacketDataStream stream)
internal override void SaveData(SpanWriter writer)
{
if (Result == ChannelConnectResult.Success)
{
stream.WriteBoolean(true, BooleanCoding.Word);
stream.WriteUInt16(0); // field_1E710
stream.WriteUInt32(0); // field_1E714
stream.WriteString(Player.ID, 12);
stream.WriteString(Player.Name, 10);
stream.WriteUInt16(Player.UnknownB);
stream.WriteUInt16(Player.UnknownC);
stream.WriteUInt16(Player.UnknownD);
stream.WriteUInt16(Player.UnknownE);
stream.WriteUInt16(Player.UnknownF);
stream.WriteUInt16(Player.UnknownG);
stream.WriteUInt16(Player.UnknownH);
stream.WriteUInt16(Player.UnknownI);
stream.WriteUInt16(Player.UnknownJ);
stream.WriteUInt16(Player.UnknownK);
stream.WriteUInt16(Player.UnknownL);
stream.WriteUInt16(Player.UnknownM);
stream.WriteUInt16(Player.UnknownN);
stream.WriteUInt16(Player.UnknownO);
stream.WriteUInt64(Player.Experience);
stream.WriteUInt64(Player.Gold);
stream.WriteUInt16(Player.Rank);
stream.WriteUInt16(Player.GuildMarkIndex);
stream.WriteString(Player.GuildName, 12);
stream.WriteUInt32(Player.UnknownS);
stream.WriteUInt32(0); // v29
stream.WriteUInt16(0); // v30
stream.WriteUInt16(Player.UnknownT);
stream.WriteUInt16(Player.UnknownU);
stream.WriteUInt16(Player.UnknownV);
stream.WriteUInt16(Player.UnknownW);
stream.WriteString(Player.UnknownX, 20);
stream.WriteString(Player.UnknownY, 20);
stream.WriteString(Player.UnknownZ, 20);
stream.WriteString(Player.UnknownAA, 20);
stream.WriteUInt16(Player.UnknownAB);
stream.WriteUInt16(Player.UnknownAC);
writer.WriteBoolean2(true);
writer.WriteUInt16(0); // field_1E710
writer.WriteUInt32(0); // field_1E714
writer.WriteStringFix(Player.ID, 12);
writer.WriteStringFix(Player.Name, 10);
writer.WriteUInt16(Player.UnknownB);
writer.WriteUInt16(Player.UnknownC);
writer.WriteUInt16(Player.UnknownD);
writer.WriteUInt16(Player.UnknownE);
writer.WriteUInt16(Player.UnknownF);
writer.WriteUInt16(Player.UnknownG);
writer.WriteUInt16(Player.UnknownH);
writer.WriteUInt16(Player.UnknownI);
writer.WriteUInt16(Player.UnknownJ);
writer.WriteUInt16(Player.UnknownK);
writer.WriteUInt16(Player.UnknownL);
writer.WriteUInt16(Player.UnknownM);
writer.WriteUInt16(Player.UnknownN);
writer.WriteUInt16(Player.UnknownO);
writer.WriteUInt64(Player.Experience);
writer.WriteUInt64(Player.Gold);
writer.WriteUInt16(Player.Rank);
writer.WriteUInt16(Player.GuildMarkIndex);
writer.WriteStringFix(Player.GuildName, 12);
writer.WriteUInt32(Player.UnknownS);
writer.WriteUInt32(0); // v29
writer.WriteUInt16(0); // v30
writer.WriteUInt16(Player.UnknownT);
writer.WriteUInt16(Player.UnknownU);
writer.WriteUInt16(Player.UnknownV);
writer.WriteUInt16(Player.UnknownW);
writer.WriteStringFix(Player.UnknownX, 20);
writer.WriteStringFix(Player.UnknownY, 20);
writer.WriteStringFix(Player.UnknownZ, 20);
writer.WriteStringFix(Player.UnknownAA, 20);
writer.WriteUInt16(Player.UnknownAB);
writer.WriteUInt16(Player.UnknownAC);
// TODO: Handle UnknownAC counting something.
}
else
{
stream.WriteBoolean(false, BooleanCoding.Word);
stream.WriteEnum(Result, true);
writer.WriteBoolean2(false);
writer.WriteEnumSafe(Result);
}
}
}

View File

@ -1,4 +1,5 @@
using System;
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
{
@ -11,8 +12,8 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(PacketDataStream stream) => throw new NotImplementedException();
internal override void LoadData(SpanReader reader) => throw new NotImplementedException();
internal override void SaveData(PacketDataStream stream) { }
internal override void SaveData(SpanWriter writer) { }
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.Net;
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
{
@ -17,12 +18,12 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(PacketDataStream stream)
internal override void LoadData(SpanReader reader)
{
PlayerID = stream.ReadString();
ChannelEndPoint = new IPEndPoint(IPAddress.Parse(stream.ReadString()), stream.ReadUInt16());
PlayerID = reader.ReadString();
ChannelEndPoint = new IPEndPoint(IPAddress.Parse(reader.ReadString()), reader.ReadUInt16());
}
internal override void SaveData(PacketDataStream stream) => throw new NotImplementedException();
internal override void SaveData(SpanWriter writer) => throw new NotImplementedException();
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.Net;
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
{
@ -18,12 +19,12 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(PacketDataStream stream) => throw new NotImplementedException();
internal override void LoadData(SpanReader reader) => throw new NotImplementedException();
internal override void SaveData(PacketDataStream stream)
internal override void SaveData(SpanWriter writer)
{
stream.WriteString(EndPoint.Address.ToString());
stream.WriteUInt16((ushort)EndPoint.Port);
writer.WriteString(EndPoint.Address.ToString());
writer.WriteUInt16((ushort)EndPoint.Port);
}
}
}

View File

@ -2,7 +2,8 @@
using System.Collections.Generic;
using System.Drawing;
using System.Net;
using Syroot.BinaryData;
using Syroot.BinaryData.Memory;
using Syroot.Worms.Mgame.GameServer.Core.IO;
namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
{
@ -18,24 +19,24 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(PacketDataStream stream) => throw new NotImplementedException();
internal override void LoadData(SpanReader reader) => throw new NotImplementedException();
internal override void SaveData(PacketDataStream stream)
internal override void SaveData(SpanWriter writer)
{
stream.WriteUInt16((ushort)Channels.Count);
writer.WriteUInt16((ushort)Channels.Count);
foreach (ChannelInfo channel in Channels)
{
stream.WriteEnum(channel.Type, true);
stream.WriteByte(channel.Coins);
stream.WriteColor(channel.Color);
stream.WriteUInt16(1); // ?
writer.WriteEnumSafe(channel.Type);
writer.WriteByte(channel.Coins);
writer.WriteColor(channel.Color);
writer.WriteUInt16(1); // ?
stream.WriteString(channel.Name);
stream.WriteByte(0); // ?
writer.WriteString(channel.Name);
writer.WriteByte(0); // ?
stream.WriteBytes(channel.EndPoint.Address.GetAddressBytes());
stream.WriteUInt16((ushort)channel.EndPoint.Port);
stream.WriteEnum(channel.Load, true);
writer.WriteBytes(channel.EndPoint.Address.GetAddressBytes());
writer.WriteUInt16((ushort)channel.EndPoint.Port);
writer.WriteEnumSafe(channel.Load);
}
}
}

View File

@ -1,4 +1,5 @@
using System;
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
{
@ -17,11 +18,11 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(PacketDataStream stream)
internal override void LoadData(SpanReader reader)
{
Count = stream.ReadUInt16();
Count = reader.ReadUInt16();
}
internal override void SaveData(PacketDataStream stream) => throw new NotImplementedException();
internal override void SaveData(SpanWriter writer) => throw new NotImplementedException();
}
}

View File

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using Syroot.BinaryData;
using Syroot.Worms.Core.IO;
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
{
@ -19,16 +18,16 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(PacketDataStream stream) => throw new NotImplementedException();
internal override void LoadData(SpanReader reader) => throw new NotImplementedException();
internal override void SaveData(PacketDataStream stream)
internal override void SaveData(SpanWriter writer)
{
stream.WriteString(UnknownA, 30);
writer.WriteStringFix(UnknownA, 30);
foreach (ChannelTop20Player top20Player in Top20)
{
stream.WriteUInt16(top20Player.Rank);
stream.WriteString(top20Player.Name, 12);
stream.WriteUInt64(top20Player.Experience);
writer.WriteUInt16(top20Player.Rank);
writer.WriteStringFix(top20Player.Name, 12);
writer.WriteUInt64(top20Player.Experience);
}
}
}

View File

@ -1,4 +1,5 @@
using System;
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
{
@ -10,8 +11,8 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(PacketDataStream stream) { }
internal override void LoadData(SpanReader reader) { }
internal override void SaveData(PacketDataStream stream) => throw new NotImplementedException();
internal override void SaveData(SpanWriter writer) => throw new NotImplementedException();
}
}

View File

@ -1,4 +1,5 @@
using System;
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
{
@ -18,14 +19,14 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(PacketDataStream stream) => throw new NotImplementedException();
internal override void LoadData(SpanReader reader) => throw new NotImplementedException();
internal override void SaveData(PacketDataStream stream)
internal override void SaveData(SpanWriter writer)
{
stream.WriteString(Unknown);
stream.WriteByte(0);
stream.WriteString(Unknown2);
stream.WriteUInt16(Version);
writer.WriteString(Unknown);
writer.WriteByte(0);
writer.WriteString(Unknown2);
writer.WriteUInt16(Version);
}
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.Net;
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
{
@ -19,22 +20,22 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(PacketDataStream stream)
internal override void LoadData(SpanReader reader)
{
Unknown1 = stream.ReadUInt16();
Logins = new LoginCredentials[stream.ReadUInt16()];
Unknown1 = reader.ReadUInt16();
Logins = new LoginCredentials[reader.ReadUInt16()];
for (int i = 0; i < Logins.Length; i++)
{
Logins[i] = new LoginCredentials
{
ID = stream.ReadString(),
Password = stream.ReadString()
ID = reader.ReadString(),
Password = reader.ReadString()
};
}
ClientIP = IPAddress.Parse(stream.ReadString());
ClientIP = IPAddress.Parse(reader.ReadString());
}
internal override void SaveData(PacketDataStream stream) => throw new NotImplementedException();
internal override void SaveData(SpanWriter writer) => throw new NotImplementedException();
}
internal class LoginCredentials

View File

@ -1,5 +1,5 @@
using System;
using Syroot.BinaryData;
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
{
@ -23,25 +23,25 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(PacketDataStream stream) => throw new NotImplementedException();
internal override void LoadData(SpanReader reader) => throw new NotImplementedException();
internal override void SaveData(PacketDataStream stream)
internal override void SaveData(SpanWriter writer)
{
bool loginSuccessful = Result == LoginResult.Success;
stream.WriteBoolean(loginSuccessful);
writer.WriteBoolean(loginSuccessful);
if (loginSuccessful)
{
stream.WriteBoolean(!HasMessageRights, BooleanCoding.Word);
stream.WriteUInt16((ushort)PlayerInfos.Length);
writer.WriteBoolean2(!HasMessageRights);
writer.WriteUInt16((ushort)PlayerInfos.Length);
foreach (LoginPlayerInfo playerInfo in PlayerInfos)
{
stream.WriteString(playerInfo.ID);
stream.WriteUInt16(playerInfo.Rank);
writer.WriteString(playerInfo.ID);
writer.WriteUInt16(playerInfo.Rank);
}
}
else
{
stream.WriteEnum(Result, true);
writer.WriteEnumSafe(Result);
}
}
}

View File

@ -1,4 +1,5 @@
using System;
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
{
@ -18,11 +19,11 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(PacketDataStream stream) => throw new NotImplementedException();
internal override void LoadData(SpanReader reader) => throw new NotImplementedException();
internal override void SaveData(PacketDataStream stream)
internal override void SaveData(SpanWriter writer)
{
stream.WriteString(Text.Replace(Environment.NewLine, "\n"));
writer.WriteString(Text.Replace(Environment.NewLine, "\n"));
}
}
}

View File

@ -1,5 +1,5 @@
using System;
using Syroot.BinaryData;
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
{
@ -17,14 +17,14 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(PacketDataStream stream)
internal override void LoadData(SpanReader reader)
{
RoundType = stream.ReadEnum<GameStartRoundType>(true);
UnknownB = stream.Read1Byte();
UnknownC = stream.Read1Byte();
RoundType = reader.ReadEnumSafe<GameStartRoundType>();
UnknownB = reader.ReadByte();
UnknownC = reader.ReadByte();
}
internal override void SaveData(PacketDataStream stream) => throw new NotImplementedException();
internal override void SaveData(SpanWriter writer) => throw new NotImplementedException();
}
internal enum GameStartRoundType : byte

View File

@ -1,5 +1,5 @@
using System;
using Syroot.BinaryData;
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
{
@ -15,11 +15,11 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(PacketDataStream stream) => throw new NotImplementedException();
internal override void LoadData(SpanReader reader) => throw new NotImplementedException();
internal override void SaveData(PacketDataStream stream)
internal override void SaveData(SpanWriter writer)
{
stream.WriteBoolean(Success, BooleanCoding.Word);
writer.WriteBoolean2(Success);
}
}
}

View File

@ -1,4 +1,6 @@
namespace Syroot.Worms.Mgame.GameServer.Packets
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets
{
/// <summary>
/// Represents a packet with an ID specifying its contents. To allow the server to instantiate child packet classes,
@ -8,8 +10,8 @@
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal abstract void LoadData(PacketDataStream stream);
internal abstract void LoadData(SpanReader reader);
internal abstract void SaveData(PacketDataStream stream);
internal abstract void SaveData(SpanWriter writer);
}
}

View File

@ -1,5 +1,4 @@
using System;
using System.Drawing;
using System.IO;
using System.Text;
using Syroot.BinaryData;
@ -22,16 +21,19 @@ namespace Syroot.Worms.Mgame.GameServer
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
}
internal PacketDataStream() : this(new MemoryStream()) { }
internal PacketDataStream(byte[] buffer) : this(new MemoryStream(buffer)) { }
private PacketDataStream(MemoryStream baseStream)
internal PacketDataStream(MemoryStream baseStream)
: base(baseStream, encoding: Encoding.GetEncoding(949), stringCoding: StringCoding.Int16CharCount)
{
_baseStream = baseStream;
}
internal PacketDataStream(MemoryStream baseStream, int offset)
: this(new MemoryStream(baseStream.GetBuffer(), offset, (int)baseStream.Length - offset)) { }
internal PacketDataStream() : this(new MemoryStream()) { }
internal PacketDataStream(byte[] buffer) : this(new MemoryStream(buffer)) { }
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
/// <summary>
@ -48,17 +50,5 @@ namespace Syroot.Worms.Mgame.GameServer
{
return ReadBytes((int)(Length - Position));
}
/// <summary>
/// Writes the given <paramref name="color"/> as an RGB0 integer value.
/// </summary>
/// <param name="color">The <see cref="Color"/> to write.</param>
internal void WriteColor(Color color)
{
WriteByte(color.R);
WriteByte(color.G);
WriteByte(color.B);
WriteByte(0);
}
}
}

View File

@ -1,5 +1,5 @@
#if DEBUG
using Syroot.BinaryData;
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets
{
@ -27,14 +27,14 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(PacketDataStream stream)
internal override void LoadData(SpanReader reader)
{
Data = stream.ReadBytes((int)stream.Length);
Data = reader.ReadBytes(reader.Length);
}
internal override void SaveData(PacketDataStream stream)
internal override void SaveData(SpanWriter writer)
{
stream.WriteBytes(Data);
writer.WriteBytes(Data);
}
}
}

View File

@ -0,0 +1,17 @@
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
{
/// <summary>
/// Represents the client request for a <see cref="ConnectReply"/>.
/// </summary>
[Packet(PacketFormat.Wwpa, 0x8001)]
internal class ConnectQuery : Packet
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(SpanReader reader) { }
internal override void SaveData(SpanWriter writer) { }
}
}

View File

@ -1,329 +0,0 @@
using System;
namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
{
/// <summary>
/// Represents packet data encryption as used in WWPA. Note that most code is a direct translation from the original
/// game assembly.
/// </summary>
/// <remarks>
/// The original implementation has the following bugs caused by specific, but rare patterns (in 1000 random blobs
/// of sizes between 1 and 1000 bytes, ~0.5% were decompressed badly):
/// - Bad calculation of decompressed bytes. The same wrong bytes are calculated by this implementation. Such data
/// may be discarded by the game as soon as it causes the final length to differ.
/// - Bad negative source buffer indices cause out-of-bounds memory to be written. Combatted in this implementation
/// by ignoring such writes and keeping 0 bytes instead.
/// </remarks>
public static class PacketCompression
{
// ---- FIELDS -------------------------------------------------------------------------------------------------
private static int _numBytesTransferred = 0;
private static int _field_4 = 4;
private static int _field_8 = 0;
private static int _field_C = 0;
private static int _field_10 = 0;
private static int[] _bufferDwords = new int[512];
private static byte[] _buffer = new byte[256];
private static int _bufferCursor = 0;
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
/// <summary>
/// Compresses the given <paramref name="decompressed"/> data.
/// </summary>
/// <param name="decompressed">The data to compress.</param>
/// <returns>The compressed data.</returns>
public static ReadOnlySpan<byte> Compress(ReadOnlySpan<byte> decompressed)
{
Compressor compressor = new Compressor();
int idx;
int bytesToRepeat;
int idxDword;
int i;
int offset;
int v11;
int v12;
int field_8;
int field_10;
byte c;
int shiftValue1;
idx = 0;
while (idx < decompressed.Length)
{
bytesToRepeat = idx - 0xFF;
if (idx - 0xFF < 0)
bytesToRepeat = 0;
idxDword = 0;
shiftValue1 = -1;
if (bytesToRepeat >= idx)
{
c = decompressed[idx++];
Write(compressor, c);
}
else
{
do
{
for (i = idx; i < decompressed.Length; ++i)
{
if (i - idx >= 0x111)
break;
if (decompressed[bytesToRepeat] != decompressed[i])
break;
++bytesToRepeat;
}
offset = idx - i;
v11 = i - idx;
v12 = offset + bytesToRepeat;
if (v11 >= 3 && v11 > idxDword)
{
idxDword = v11;
shiftValue1 = idx - 12;
if (v11 == 0x111)
break;
}
bytesToRepeat = v12 + 1;
}
while (bytesToRepeat < idx);
if (idxDword != 0)
{
TransferBuffer(compressor);
compressor.Compress(true);
if (idxDword >= 18)
{
compressor.Shift(0, 4);
compressor.Shift(shiftValue1, 8);
compressor.Shift(idxDword - 18, 8);
field_10 = _field_10;
++_field_C;
_field_10 = idxDword - 3 + field_10;
}
else
{
compressor.Shift(idxDword - 2, 4);
compressor.Shift(shiftValue1 - 1, 8);
field_8 = _field_8;
++_field_4;
_field_8 = idxDword - 2 + field_8;
}
idx += idxDword;
++_bufferDwords[idxDword];
}
else
{
c = decompressed[idx++];
Write(compressor, c);
}
}
}
TransferBuffer(compressor);
compressor.Compress(true);
compressor.Shift(0, 4);
compressor.Shift(0, 8);
return compressor.Compressed.AsSpan(0, compressor.Cursor);
}
public static ReadOnlySpan<byte> Decompress(ReadOnlySpan<byte> compressed)
{
Decompressor decompressor = new Decompressor(compressed);
byte[] decompressed = new byte[2048];
int idx;
int bytesToCopyRemain;
int idxCopySrc;
int v12;
int v13;
int bytesToCopy;
idx = 0;
while (true)
{
while (true)
{
while (decompressor.sub_4C0BA0() == 0)
{
bytesToCopy = decompressor.GetBytesToCopy(8);
if (bytesToCopy != -1)
{
++bytesToCopy;
do
{
decompressed[idx++] = decompressor.Read();
--bytesToCopy;
} while (bytesToCopy != 0);
}
}
bytesToCopy = decompressor.GetBytesToCopy(4) + 2;
if (bytesToCopy <= 2)
break;
bytesToCopy = decompressor.GetBytesToCopy(8) + 1;
bytesToCopyRemain = bytesToCopy - 1;
if (bytesToCopy != 0)
{
++bytesToCopyRemain;
do
{
idxCopySrc = idx++ - bytesToCopy;
--bytesToCopyRemain;
if (idxCopySrc >= 0) // Bugfix: Original implementation may calculate negative indices.
decompressed[idx - 1] = decompressed[idxCopySrc];
} while (bytesToCopyRemain != 0);
}
}
bytesToCopy = decompressor.GetBytesToCopy(8);
if (bytesToCopy == 0)
break;
v12 = decompressor.GetBytesToCopy(8);
v13 = v12 + 18;
bytesToCopyRemain = v12 + 17;
if (v13 != 0)
{
++bytesToCopyRemain;
do
{
idxCopySrc = idx++ - bytesToCopy;
--bytesToCopyRemain;
decompressed[idx - 1] = decompressed[idxCopySrc];
} while (bytesToCopyRemain != 0);
}
}
return decompressed.AsSpan(0, idx);
}
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
private static void TransferBuffer(Compressor compressor)
{
int bufferCursor;
int i;
bufferCursor = _bufferCursor;
if (bufferCursor != 0)
{
_numBytesTransferred += bufferCursor;
compressor.Compress(false);
compressor.Shift(_bufferCursor - 1, 8);
for (i = 0; i < _bufferCursor; ++i)
compressor.Write(_buffer[i]);
_bufferCursor = 0;
}
}
private static void Write(Compressor compressor, byte c)
{
_buffer[_bufferCursor++] = c;
if (_bufferCursor >= _buffer.Length)
TransferBuffer(compressor);
}
// ---- CLASSES, STRUCTS & ENUMS -------------------------------------------------------------------------------
private class Compressor
{
internal byte[] Compressed = new byte[1024];
internal int Cursor = 1;
private int _cursorCompress = 0;
private int _shift = 0;
internal void Compress(bool bShift)
{
int shift;
int cursor;
int cursorCompress;
if (bShift)
{
Compressed[_cursorCompress] |= (byte)(0x80 >> _shift);
}
shift = _shift + 1;
_shift = shift;
if (shift == 8)
{
cursor = Cursor;
_cursorCompress = Cursor++;
cursorCompress = _cursorCompress;
Cursor = cursor + 1;
Compressed[cursorCompress] = 0;
_shift = 0;
}
}
internal void Shift(int value, int shiftPlus1)
{
int shift;
int prevShift;
shift = shiftPlus1 - 1;
if (shiftPlus1 != 0)
{
do
{
Compress(((value >> shift) & 1) != 0);
prevShift = shift--;
} while (prevShift != 0);
}
}
internal void Write(byte c)
{
Compressed[Cursor++] = c;
}
}
private class Decompressor
{
private readonly byte[] _compressed;
private int _compressedCursor = 0;
private byte _field_C;
private byte _field_D;
internal Decompressor(ReadOnlySpan<byte> compressed)
{
_compressed = compressed.ToArray();
byte c = Read();
_field_C = (byte)(2 * c | 1);
_field_D = (byte)((uint)c >> 7);
}
internal byte Read()
{
return _compressed[_compressedCursor++];
}
internal int GetBytesToCopy(int numCalls)
{
if (numCalls == 0)
return 0;
int bytesToCopy = 0;
do
{
numCalls--;
bytesToCopy = sub_4C0BA0() + 2 * bytesToCopy;
} while (numCalls != 0);
return bytesToCopy;
}
internal int sub_4C0BA0()
{
byte field_D = _field_D;
_field_D = (byte)(_field_C >> 7);
_field_C *= 2;
if (_field_C == 0)
{
byte c = Read();
_field_C = (byte)(2 * c | 1);
_field_D = (byte)(c >> 7);
}
return field_D;
}
}
}
}

View File

@ -10,7 +10,9 @@
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.2.0" />
<PackageReference Include="Syroot.BinaryData.Memory" Version="5.2.0-alpha1" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.5.1" />
<ProjectReference Include="..\Syroot.Worms.Mgame\Syroot.Worms.Mgame.csproj" />
<ProjectReference Include="..\Syroot.Worms\Syroot.Worms.csproj" />
<None Update="ServerConfig.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>

View File

@ -5,11 +5,11 @@ namespace Syroot.Worms.Mgame
/// <summary>
/// Represents instances of common <see cref="Encoding"/> pages.
/// </summary>
internal static class Encodings
public static class Encodings
{
// ---- FIELDS -------------------------------------------------------------------------------------------------
internal static readonly Encoding Win949;
public static readonly Encoding Win949;
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------

View File

@ -27,7 +27,7 @@ namespace Syroot.Worms.Mgame
private static int _field_C = 0;
private static int _field_10 = 0;
private static int[] _bufferDwords = new int[512];
private static readonly int[] _bufferDwords = new int[512];
private static byte[] _buffer = new byte[256];
private static int _bufferCursor = 0;
@ -39,7 +39,7 @@ namespace Syroot.Worms.Mgame
/// </summary>
/// <param name="decompressed">The data to compress.</param>
/// <returns>The compressed data.</returns>
public static ReadOnlySpan<byte> Compress(ReadOnlySpan<byte> decompressed)
public static Span<byte> Compress(ReadOnlySpan<byte> decompressed)
{
Compressor compressor = new Compressor();
int idx;
@ -129,10 +129,9 @@ namespace Syroot.Worms.Mgame
compressor.Shift(0, 8);
return compressor.Compressed.AsSpan(0, compressor.Cursor);
}
public static ReadOnlySpan<byte> Decompress(ReadOnlySpan<byte> compressed)
public static Span<byte> Decompress(ReadOnlySpan<byte> compressed)
{
Decompressor decompressor = new Decompressor(compressed);
byte[] decompressed = new byte[2048];
@ -150,7 +149,7 @@ namespace Syroot.Worms.Mgame
{
while (true)
{
while (decompressor.sub_4C0BA0() == 0)
while (decompressor.Sub_4C0BA0() == 0)
{
bytesToCopy = decompressor.GetBytesToCopy(8);
if (bytesToCopy != -1)
@ -309,12 +308,12 @@ namespace Syroot.Worms.Mgame
do
{
numCalls--;
bytesToCopy = sub_4C0BA0() + 2 * bytesToCopy;
bytesToCopy = Sub_4C0BA0() + 2 * bytesToCopy;
} while (numCalls != 0);
return bytesToCopy;
}
internal int sub_4C0BA0()
internal int Sub_4C0BA0()
{
byte field_D = _field_D;
_field_D = (byte)(_field_C >> 7);

View File

@ -4,9 +4,7 @@
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Syroot.BinaryData" Version="5.1.0-beta1" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Syroot.BinaryData" Version="5.1.0" />
<ProjectReference Include="..\Syroot.Worms.Armageddon.ProjectX\Syroot.Worms.Armageddon.ProjectX.csproj" />
<ProjectReference Include="..\Syroot.Worms.Armageddon\Syroot.Worms.Armageddon.csproj" />
<ProjectReference Include="..\Syroot.Worms.Mgame\Syroot.Worms.Mgame.csproj" />

View File

@ -19,7 +19,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Syroot.BinaryData.Serialization" Version="5.0.0" />
<PackageReference Include="Syroot.BinaryData" Version="5.1.0-beta1" />
<PackageReference Include="Syroot.BinaryData" Version="5.1.0" />
<PackageReference Include="System.Drawing.Common" Version="4.5.1" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.5.1" />
</ItemGroup>