mirror of
https://gitlab.com/Syroot/Worms.git
synced 2025-01-27 22:27:58 +03:00
Use new BinaryData package to work on spans rather than streams.
This commit is contained in:
parent
fcc2c74399
commit
7852ef9d5a
156
src/Syroot.Worms.Mgame.GameServer/Client.OnlineWorms.cs
Normal file
156
src/Syroot.Worms.Mgame.GameServer/Client.OnlineWorms.cs
Normal 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
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
14
src/Syroot.Worms.Mgame.GameServer/Client.WorldPartyAqua.cs
Normal file
14
src/Syroot.Worms.Mgame.GameServer/Client.WorldPartyAqua.cs
Normal 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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -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) --------------------------------------------------------------------------------------
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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) { }
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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) { }
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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>
|
||||
|
@ -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 ------------------------------------------------------------------------------
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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" />
|
||||
|
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user