Implement WWPA packets, update OW ones to Span parsing, rename encodings.

This commit is contained in:
Ray Koopa 2019-01-19 02:17:20 +01:00
parent 899c031840
commit 587ac06330
35 changed files with 341 additions and 93 deletions

View File

@ -42,7 +42,7 @@ namespace Syroot.Worms.Mgame.GameServer
});
// Send channels. The port is abused to identify the channel later on.
SendPacket(new ChannelInfosReply
SendPacket(new ChannelListReply
{
Channels = new[]
{

View File

@ -1,4 +1,5 @@
using Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua;
using System.Collections.Generic;
using Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua;
namespace Syroot.Worms.Mgame.GameServer
{
@ -6,9 +7,21 @@ namespace Syroot.Worms.Mgame.GameServer
{
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
public void HandleWWPAConnect(ConnectQuery packet)
public void HandleWwpaConnect(ConnectQuery packet)
{
SendPacket(new ConnectReply { ServerVersion = _server.Config.Version });
}
public void HandleWwpaLogin(LoginQuery packet)
{
SendPacket(new LoginReply { Result = LoginResult.Success });
}
public void HandleWwpaLoginAcknowledge(ChannelListQuery packet)
{
SendPacket(new ChannelListReply { Channels = new List<ChannelInfo>() });
}
public void HandleWwpaDisconnectQuery(DisconnectQuery packet) { }
}
}

View File

@ -35,9 +35,15 @@ namespace Syroot.Worms.Mgame.GameServer
};
}
#if DEBUG
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
public void HandleRawPacket(RawPacket packet) { }
#endif
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
private string FormatPacket(Packet packet, string direction)
=> $"{TcpClient.Client.RemoteEndPoint} {direction} {packet.GetType().Name}{ObjectDumper.Dump(packet)}";
}
}
}

View File

@ -0,0 +1,19 @@
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Core.IO
{
/// <summary>
/// Represents extension methods for <see cref="SpanReader"/> instances.
/// </summary>
internal static class SpanReaderExtensions
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
/// <summary>
/// Reads the remaining bytes that are available.
/// </summary>
/// <param name="self">The extended instance.</param>
/// <returns>The remaining bytes in the reader.</returns>
internal static byte[] ReadToEnd(this ref SpanReader self) => self.ReadBytes(self.Length - self.Position);
}
}

View File

@ -15,7 +15,7 @@ namespace Syroot.Worms.Mgame.GameServer.Core.IO
/// </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)
internal static void WriteColor(this ref SpanWriter self, Color color)
{
self.WriteByte(color.R);
self.WriteByte(color.G);

View File

@ -104,7 +104,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
SendOWServerPacket(attribute.ID, packet);
break;
case PacketFormat.Wwpa:
SaveWwpaPacket(attribute.ID, packet);
SendWwpaPacket(attribute.ID, packet, false);
break;
default:
throw new IOException("Cannot send unknown packet format.");
@ -145,7 +145,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
int dataSize = _tcpStream.ReadUInt16();
int id = _tcpStream.Read1Byte();
// Read data.
SpanReader reader = new SpanReader(_tcpStream.ReadBytes(dataSize), encoding: Encodings.Win949);
SpanReader reader = new SpanReader(_tcpStream.ReadBytes(dataSize), encoding: Encodings.Korean);
// Read tail.
ushort endTag = _tcpStream.ReadUInt16();
if (endTag != _owTagEndChannel)
@ -153,7 +153,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
// Instantiate, deserialize, and return packet.
Packet packet = PacketFactory.Create(PacketFormat.OWChannel, id);
packet.LoadData(reader);
packet.Load(ref reader);
return packet;
}
@ -162,11 +162,11 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
// Read head.
int dataSize = _tcpStream.ReadUInt16();
// Read data.
SpanReader reader = new SpanReader(_tcpStream.ReadBytes(dataSize), encoding: Encodings.Win949);
SpanReader reader = new SpanReader(_tcpStream.ReadBytes(dataSize), encoding: Encodings.Korean);
// Instantiate, deserialize, and return packet.
Packet packet = PacketFactory.Create(PacketFormat.OWServer, tag);
packet.LoadData(reader);
packet.Load(ref reader);
return packet;
}
@ -174,9 +174,9 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
{
// Read head.
if (!_tcpStream.ReadBoolean())
throw new IOException("Unexpected WWPA packet head2.");
throw new IOException("Unexpected WWPA packet bHead2.");
if (_tcpStream.ReadBoolean())
throw new IOException("Unexpected WWPA packet head3.");
throw new IOException("Unexpected WWPA packet bHead3.");
if (!_tcpStream.ReadBoolean())
throw new IOException("Unexpected WWPA packet bIsCompressed.");
int decompressedSize = _tcpStream.ReadUInt16();
@ -191,18 +191,19 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
throw new IOException("Invalid WWPA packet end tag.");
// Instantiate, deserialize, and return packet.
SpanReader reader = new SpanReader(PacketCompression.Decompress(compressedData), encoding: Encodings.Win949);
SpanReader reader = new SpanReader(PacketCompression.Decompress(compressedData), encoding: Encodings.Korean);
int id = reader.ReadInt32();
Packet packet = PacketFactory.Create(PacketFormat.Wwpa, id);
packet.LoadData(reader.Slice());
SpanReader dataReader = reader.Slice();
packet.Load(ref dataReader);
return packet;
}
private void SendOWChannelPacket(int id, Packet packet)
{
// Retrieve data. Must have at least 1 byte.
SpanWriter writer = new SpanWriter(new byte[_maxDataSize], encoding: Encodings.Win949);
packet.SaveData(writer);
SpanWriter writer = new SpanWriter(new byte[_maxDataSize], encoding: Encodings.Korean);
packet.Save(ref writer);
writer.Position = Math.Max(1, writer.Position);
// Send head.
@ -221,8 +222,8 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
private void SendOWServerPacket(int id, Packet packet)
{
// Retrieve data.
SpanWriter writer = new SpanWriter(new byte[_maxDataSize], encoding: Encodings.Win949);
packet.SaveData(writer);
SpanWriter writer = new SpanWriter(new byte[_maxDataSize], encoding: Encodings.Korean);
packet.Save(ref writer);
// Send head.
_tcpStream.WriteUInt16((ushort)id);
@ -232,27 +233,36 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
_tcpStream.Write(writer.Span);
}
private void SaveWwpaPacket(int id, Packet packet)
private void SendWwpaPacket(int id, Packet packet, bool compress)
{
// Retrieve (decompressed) data size.
SpanWriter writer = new SpanWriter(new byte[_maxDataSize], encoding: Encodings.Win949);
packet.SaveData(writer);
ReadOnlySpan<byte> compressedData = PacketCompression.Compress(writer.Span);
// Retrieve (decompressed) data.
SpanWriter writer = new SpanWriter(new byte[_maxDataSize], encoding: Encodings.Korean);
writer.WriteInt32(id);
packet.Save(ref writer);
// Send head.
// Send head and data.
_tcpStream.WriteUInt16(_wwpaTagStart);
_tcpStream.WriteBoolean(true);
_tcpStream.WriteBoolean(false);
_tcpStream.WriteBoolean(true); // isCompressed
_tcpStream.WriteUInt16((ushort)writer.Span.Length);
_tcpStream.WriteUInt32((uint)compressedData.Length);
_tcpStream.WriteInt32(1); // Apparently only needs to be same as in tail.
// Send data.
_tcpStream.Write(compressedData);
_tcpStream.WriteBoolean(true); // bHead2 (unknown)
_tcpStream.WriteBoolean(false); // bHead3 (unknown)
_tcpStream.WriteBoolean(compress);
if (compress)
{
ReadOnlySpan<byte> compressedData = PacketCompression.Compress(writer.Span);
_tcpStream.WriteUInt16((ushort)writer.Position); // decompressed size
_tcpStream.WriteUInt32((uint)compressedData.Length); // compressed size
_tcpStream.WriteInt32(1); // index
_tcpStream.Write(compressedData);
}
else
{
_tcpStream.WriteUInt16(0); // unused
_tcpStream.WriteUInt32((ushort)writer.Position); // raw size
_tcpStream.WriteInt32(1); // index
_tcpStream.Write(writer.Span.Slice(0, writer.Position));
}
// Send tail.
_tcpStream.WriteInt32(1); // Apparently only needs to be same as in head.
_tcpStream.WriteInt32(1); // index (must equal other)
_tcpStream.WriteUInt16(_wwpaTagEnd);
}
}

View File

@ -25,7 +25,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(SpanReader reader)
internal override void Load(ref SpanReader reader)
{
Players = new List<ChannelConnectPlayerCredentials>
{
@ -51,7 +51,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
UnknownB = reader.ReadByte();
}
internal override void SaveData(SpanWriter writer) => throw new NotImplementedException();
internal override void Save(ref SpanWriter writer) => throw new NotImplementedException();
}
internal class ChannelConnectPlayerCredentials

View File

@ -17,9 +17,9 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(SpanReader reader) => throw new NotImplementedException();
internal override void Load(ref SpanReader reader) => throw new NotImplementedException();
internal override void SaveData(SpanWriter writer)
internal override void Save(ref SpanWriter writer)
{
if (Result == ChannelConnectResult.Success)
{

View File

@ -12,8 +12,8 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(SpanReader reader) => throw new NotImplementedException();
internal override void Load(ref SpanReader reader) => throw new NotImplementedException();
internal override void SaveData(SpanWriter writer) { }
internal override void Save(ref SpanWriter writer) { }
}
}

View File

@ -18,12 +18,12 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(SpanReader reader)
internal override void Load(ref SpanReader reader)
{
PlayerID = reader.ReadString();
ChannelEndPoint = new IPEndPoint(IPAddress.Parse(reader.ReadString()), reader.ReadUInt16());
}
internal override void SaveData(SpanWriter writer) => throw new NotImplementedException();
internal override void Save(ref SpanWriter writer) => throw new NotImplementedException();
}
}

View File

@ -19,11 +19,11 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(SpanReader reader) => throw new NotImplementedException();
internal override void Load(ref SpanReader reader) => throw new NotImplementedException();
internal override void SaveData(SpanWriter writer)
internal override void Save(ref SpanWriter writer)
{
writer.WriteString(EndPoint.Address.ToString());
writer.WriteString2(EndPoint.Address.ToString());
writer.WriteUInt16((ushort)EndPoint.Port);
}
}

View File

@ -11,7 +11,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
/// Represents an additional server response to a <see cref="LoginQuery"/>, providing available server channels.
/// </summary>
[Packet(PacketFormat.OWServer, 0x80C9)]
internal class ChannelInfosReply : Packet
internal class ChannelListReply : Packet
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
@ -19,9 +19,9 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(SpanReader reader) => throw new NotImplementedException();
internal override void Load(ref SpanReader reader) => throw new NotImplementedException();
internal override void SaveData(SpanWriter writer)
internal override void Save(ref SpanWriter writer)
{
writer.WriteUInt16((ushort)Channels.Count);
foreach (ChannelInfo channel in Channels)
@ -31,7 +31,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
writer.WriteColor(channel.Color);
writer.WriteUInt16(1); // ?
writer.WriteString(channel.Name);
writer.WriteString2(channel.Name);
writer.WriteByte(0); // ?
writer.WriteBytes(channel.EndPoint.Address.GetAddressBytes());

View File

@ -18,11 +18,11 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(SpanReader reader)
internal override void Load(ref SpanReader reader)
{
Count = reader.ReadUInt16();
}
internal override void SaveData(SpanWriter writer) => throw new NotImplementedException();
internal override void Save(ref SpanWriter writer) => throw new NotImplementedException();
}
}

View File

@ -18,9 +18,9 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(SpanReader reader) => throw new NotImplementedException();
internal override void Load(ref SpanReader reader) => throw new NotImplementedException();
internal override void SaveData(SpanWriter writer)
internal override void Save(ref SpanWriter writer)
{
writer.WriteStringFix(UnknownA, 30);
foreach (ChannelTop20Player top20Player in Top20)

View File

@ -11,8 +11,8 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(SpanReader reader) { }
internal override void Load(ref SpanReader reader) { }
internal override void SaveData(SpanWriter writer) => throw new NotImplementedException();
internal override void Save(ref SpanWriter writer) => throw new NotImplementedException();
}
}

View File

@ -19,13 +19,13 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(SpanReader reader) => throw new NotImplementedException();
internal override void Load(ref SpanReader reader) => throw new NotImplementedException();
internal override void SaveData(SpanWriter writer)
internal override void Save(ref SpanWriter writer)
{
writer.WriteString(Unknown);
writer.WriteString2(Unknown);
writer.WriteByte(0);
writer.WriteString(Unknown2);
writer.WriteString2(Unknown2);
writer.WriteUInt16(Version);
}
}

View File

@ -20,7 +20,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(SpanReader reader)
internal override void Load(ref SpanReader reader)
{
Unknown1 = reader.ReadUInt16();
Logins = new LoginCredentials[reader.ReadUInt16()];
@ -35,7 +35,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
ClientIP = IPAddress.Parse(reader.ReadString());
}
internal override void SaveData(SpanWriter writer) => throw new NotImplementedException();
internal override void Save(ref SpanWriter writer) => throw new NotImplementedException();
}
internal class LoginCredentials

View File

@ -23,9 +23,9 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(SpanReader reader) => throw new NotImplementedException();
internal override void Load(ref SpanReader reader) => throw new NotImplementedException();
internal override void SaveData(SpanWriter writer)
internal override void Save(ref SpanWriter writer)
{
bool loginSuccessful = Result == LoginResult.Success;
writer.WriteBoolean(loginSuccessful);
@ -35,7 +35,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
writer.WriteUInt16((ushort)PlayerInfos.Length);
foreach (LoginPlayerInfo playerInfo in PlayerInfos)
{
writer.WriteString(playerInfo.ID);
writer.WriteString2(playerInfo.ID);
writer.WriteUInt16(playerInfo.Rank);
}
}

View File

@ -19,11 +19,11 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(SpanReader reader) => throw new NotImplementedException();
internal override void Load(ref SpanReader reader) => throw new NotImplementedException();
internal override void SaveData(SpanWriter writer)
internal override void Save(ref SpanWriter writer)
{
writer.WriteString(Text.Replace(Environment.NewLine, "\n"));
writer.WriteString2(Text.Replace(Environment.NewLine, "\n"));
}
}
}

View File

@ -17,14 +17,14 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(SpanReader reader)
internal override void Load(ref SpanReader reader)
{
RoundType = reader.ReadEnumSafe<GameStartRoundType>();
UnknownB = reader.ReadByte();
UnknownC = reader.ReadByte();
}
internal override void SaveData(SpanWriter writer) => throw new NotImplementedException();
internal override void Save(ref SpanWriter writer) => throw new NotImplementedException();
}
internal enum GameStartRoundType : byte

View File

@ -15,9 +15,9 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(SpanReader reader) => throw new NotImplementedException();
internal override void Load(ref SpanReader reader) => throw new NotImplementedException();
internal override void SaveData(SpanWriter writer)
internal override void Save(ref SpanWriter writer)
{
writer.WriteBoolean2(Success);
}

View File

@ -10,8 +10,8 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal abstract void LoadData(SpanReader reader);
internal abstract void Load(ref SpanReader reader);
internal abstract void SaveData(SpanWriter writer);
internal abstract void Save(ref SpanWriter writer);
}
}

View File

@ -27,15 +27,9 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(SpanReader reader)
{
Data = reader.ReadBytes(reader.Length);
}
internal override void Load(ref SpanReader reader) => Data = reader.ReadBytes(reader.Length);
internal override void SaveData(SpanWriter writer)
{
writer.WriteBytes(Data);
}
internal override void Save(ref SpanWriter writer) => writer.WriteBytes(Data);
}
}
#endif

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="ChannelListReply"/>.
/// </summary>
[Packet(PacketFormat.Wwpa, 0x801E)]
internal class ChannelListQuery : Packet
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader) { }
internal override void Save(ref SpanWriter writer) { }
}
}

View File

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
{
/// <summary>
/// Represents the server reply to a <see cref="ChannelListQuery"/>.
/// </summary>
[Packet(PacketFormat.Wwpa, 0x801F)]
internal class ChannelListReply : Packet
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
public IList<ChannelInfo> Channels { get; set; }
public byte Unknown { get; set; }
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader) => throw new NotImplementedException();
internal override void Save(ref SpanWriter writer)
{
writer.WriteUInt16((ushort)Channels.Count);
writer.WriteByte(Unknown);
writer.Align(4);
foreach (ChannelInfo channel in Channels)
{
}
}
}
internal class ChannelInfo
{
}
}

View File

@ -10,8 +10,8 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void LoadData(SpanReader reader) { }
internal override void Load(ref SpanReader reader) { }
internal override void SaveData(SpanWriter writer) { }
internal override void Save(ref SpanWriter writer) { }
}
}

View File

@ -0,0 +1,39 @@
using System;
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
{
/// <summary>
/// Represents the server response to a <see cref="ConnectQuery"/>.
/// </summary>
[Packet(PacketFormat.Wwpa, 0x8002)]
internal class ConnectReply : Packet
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
/// <summary>
/// Gets or sets an error message displayed to prevent the connection attempt. This property must be
/// <see langword="null"/> to allow further communication.
/// </summary>
internal string ErrorMessage { get; set; }
/// <summary>
/// Gets or sets the server version reported to the client, and checked by it to allow further communication.
/// </summary>
internal ushort ServerVersion { get; set; }
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader) => throw new NotImplementedException();
internal override void Save(ref SpanWriter writer)
{
bool connectionFailed = ErrorMessage != null;
writer.WriteBoolean4(connectionFailed);
if (connectionFailed)
writer.WriteString2(ErrorMessage);
else
writer.WriteUInt16(ServerVersion);
}
}
}

View File

@ -0,0 +1,17 @@
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
{
/// <summary>
/// Represents the client packet probably sent when it notifies about disconnecting.
/// </summary>
[Packet(PacketFormat.Wwpa, 0x801B)]
internal class DisconnectQuery : Packet
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader) { }
internal override void Save(ref SpanWriter writer) { }
}
}

View File

@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
{
/// <summary>
/// Represents the client request for a <see cref="LoginReply"/>.
/// </summary>
[Packet(PacketFormat.Wwpa, 0x8019)]
internal class LoginQuery : Packet
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
/// <summary>
/// Gets or sets the names and passwords of the players to login.
/// </summary>
public IList<LoginCredentials> Logins { get; set; }
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader)
{
Logins = new List<LoginCredentials> { ReadCredentials(ref reader) };
if (reader.ReadBoolean())
Logins.Add(ReadCredentials(ref reader));
}
internal override void Save(ref SpanWriter writer) => throw new NotImplementedException();
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
private static LoginCredentials ReadCredentials(ref SpanReader reader) => new LoginCredentials
{
UserName = reader.ReadString2(),
Password = reader.ReadString2()
};
}
internal class LoginCredentials
{
/// <summary>
/// Gets or sets the name of the player to login.
/// </summary>
internal string UserName { get; set; }
/// <summary>
/// Gets or sets the password with which the player profile is authenticated.
/// </summary>
internal string Password { get; set; }
}
}

View File

@ -0,0 +1,43 @@
using System;
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
{
/// <summary>
/// Represents the server response to a <see cref="LoginQuery"/>.
/// </summary>
[Packet(PacketFormat.Wwpa, 0x801A)]
internal class LoginReply : Packet
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
public LoginResult Result { get; set; }
public byte UnknownA { get; set; }
public ushort UnknownB { get; set; }
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader) => throw new NotImplementedException();
internal override void Save(ref SpanWriter writer)
{
writer.WriteEnumSafe(Result);
if (Result == LoginResult.Success)
{
writer.WriteByte(UnknownA);
writer.WriteUInt16(UnknownB);
}
}
}
internal enum LoginResult : byte
{
Success = 0,
SaveInfoOnly = 12,
NicknameDoesNotExist = 14,
LoginFailed = 15,
FailedToFindUser = 99
}
}

View File

@ -4,7 +4,7 @@
"Port": 17022,
"Name": "Mgame Worms Private Server",
"Region": "Global",
"Version": 114,
"Version": 34, // 114 for OW, 34 for WWPA
// Debugging settings (optional)
"SendDelay": 0 // milliseconds to sleep before sending packets (simulate network load)

View File

@ -9,14 +9,14 @@ namespace Syroot.Worms.Mgame
{
// ---- FIELDS -------------------------------------------------------------------------------------------------
public static readonly Encoding Win949;
public static readonly Encoding Korean;
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
static Encodings()
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
Win949 = Encoding.GetEncoding(949);
Korean = Encoding.GetEncoding("ks_c_5601-1987"); // codepage 949
}
}
}

View File

@ -50,7 +50,7 @@ namespace Syroot.Worms.Mgame
MemoryMappedFile mappedFile = MemoryMappedFile.CreateNew(mapName, 1266,
MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.None, HandleInheritability.Inheritable);
using (BinaryStream stream = new BinaryStream(mappedFile.CreateViewStream(),
encoding: Encodings.Win949, stringCoding: StringCoding.ZeroTerminated))
encoding: Encodings.Korean, stringCoding: StringCoding.ZeroTerminated))
{
stream.WriteString(Publisher, 16);
stream.WriteString(Unknown, 20);

View File

@ -63,7 +63,7 @@ namespace Syroot.Worms.Mgame
{
Elements.Add(new LpdElement
{
FileName = stream.ReadString(StringCoding.Int32CharCount, Encodings.Win949),
FileName = stream.ReadString(StringCoding.Int32CharCount, Encodings.Korean),
Rectangle = new Rectangle(stream.ReadInt32(), stream.ReadInt32(), stream.ReadInt32(), stream.ReadInt32()),
Properties = stream.ReadInt32(),
Version = stream.ReadInt32()

View File

@ -40,7 +40,7 @@ namespace Syroot.Worms.Mgame
using (MemoryStream inStream = new MemoryStream(new byte[_bufferSize]))
{
// Write input into a buffer. Required to loop over the input password end.
inStream.WriteString(data, StringCoding.ZeroTerminated, Encodings.Win949);
inStream.WriteString(data, StringCoding.ZeroTerminated, Encodings.Korean);
inStream.Position = 0;
using (MemoryStream outStream = new MemoryStream(new byte[_bufferSize]))
{
@ -57,7 +57,7 @@ namespace Syroot.Worms.Mgame
}
// Return the encrypted password as a zero-terminated ASCII string.
outStream.Position = 0;
return outStream.ReadString(StringCoding.ZeroTerminated, Encodings.Win949);
return outStream.ReadString(StringCoding.ZeroTerminated, Encodings.Korean);
}
}
}
@ -73,7 +73,7 @@ namespace Syroot.Worms.Mgame
using (MemoryStream inStream = new MemoryStream(new byte[_bufferSize]))
{
// Write input into a buffer. Required to loop over the input password end.
inStream.WriteString(data, StringCoding.Raw, Encodings.Win949);
inStream.WriteString(data, StringCoding.Raw, Encodings.Korean);
inStream.Position = 0;
using (MemoryStream outStream = new MemoryStream(new byte[_bufferSize]))
{
@ -93,7 +93,7 @@ namespace Syroot.Worms.Mgame
}
// Return the decrypted password as a zero-terminated ASCII string.
outStream.Position = 0;
return outStream.ReadString(StringCoding.ZeroTerminated, Encodings.Win949);
return outStream.ReadString(StringCoding.ZeroTerminated, Encodings.Korean);
}
}
}