From 587ac06330c966cf492644860245243261bb5156 Mon Sep 17 00:00:00 2001 From: Ray Koopa Date: Sat, 19 Jan 2019 02:17:20 +0100 Subject: [PATCH] Implement WWPA packets, update OW ones to Span parsing, rename encodings. --- .../Client.OnlineWorms.cs | 2 +- .../Client.WorldPartyAqua.cs | 19 +++++- src/Syroot.Worms.Mgame.GameServer/Client.cs | 8 ++- .../Core/IO/SpanReaderExtensions.cs | 19 ++++++ .../Core/IO/SpanWriterExtensions.cs | 2 +- .../Packets/AppConnection.cs | 68 +++++++++++-------- .../OnlineWorms/ChannelConnectQuery.cs | 4 +- .../OnlineWorms/ChannelConnectReply.cs | 4 +- .../OnlineWorms/ChannelEnterFinishReply.cs | 4 +- .../Packets/OnlineWorms/ChannelEnterQuery.cs | 4 +- .../Packets/OnlineWorms/ChannelEnterReply.cs | 6 +- ...annelInfosReply.cs => ChannelListReply.cs} | 8 +-- .../Packets/OnlineWorms/ChannelTop20Query.cs | 4 +- .../Packets/OnlineWorms/ChannelTop20Reply.cs | 4 +- .../Packets/OnlineWorms/ConnectQuery.cs | 4 +- .../Packets/OnlineWorms/ConnectReply.cs | 8 +-- .../Packets/OnlineWorms/LoginQuery.cs | 4 +- .../Packets/OnlineWorms/LoginReply.cs | 6 +- .../Packets/OnlineWorms/ServerInfoReply.cs | 6 +- .../OnlineWorms/StartSingleGameQuery.cs | 4 +- .../OnlineWorms/StartSingleGameReply.cs | 4 +- .../Packets/Packet.cs | 4 +- .../Packets/RawPacket.cs | 10 +-- .../WorldPartyAqua/ChannelListQuery.cs | 17 +++++ .../WorldPartyAqua/ChannelListReply.cs | 38 +++++++++++ .../Packets/WorldPartyAqua/ConnectQuery.cs | 4 +- .../Packets/WorldPartyAqua/ConnectReply.cs | 39 +++++++++++ .../Packets/WorldPartyAqua/DisconnectQuery.cs | 17 +++++ .../Packets/WorldPartyAqua/LoginQuery.cs | 52 ++++++++++++++ .../Packets/WorldPartyAqua/LoginReply.cs | 43 ++++++++++++ .../ServerConfig.json | 2 +- src/Syroot.Worms.Mgame/Encodings.cs | 4 +- src/Syroot.Worms.Mgame/LaunchConfig.cs | 2 +- src/Syroot.Worms.Mgame/Lpd.cs | 2 +- src/Syroot.Worms.Mgame/PasswordCrypto.cs | 8 +-- 35 files changed, 341 insertions(+), 93 deletions(-) create mode 100644 src/Syroot.Worms.Mgame.GameServer/Core/IO/SpanReaderExtensions.cs rename src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/{ChannelInfosReply.cs => ChannelListReply.cs} (92%) create mode 100644 src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/ChannelListQuery.cs create mode 100644 src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/ChannelListReply.cs create mode 100644 src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/ConnectReply.cs create mode 100644 src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/DisconnectQuery.cs create mode 100644 src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/LoginQuery.cs create mode 100644 src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/LoginReply.cs diff --git a/src/Syroot.Worms.Mgame.GameServer/Client.OnlineWorms.cs b/src/Syroot.Worms.Mgame.GameServer/Client.OnlineWorms.cs index 7ccf0c4..6f7cdc2 100644 --- a/src/Syroot.Worms.Mgame.GameServer/Client.OnlineWorms.cs +++ b/src/Syroot.Worms.Mgame.GameServer/Client.OnlineWorms.cs @@ -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[] { diff --git a/src/Syroot.Worms.Mgame.GameServer/Client.WorldPartyAqua.cs b/src/Syroot.Worms.Mgame.GameServer/Client.WorldPartyAqua.cs index 4e28145..426bcd6 100644 --- a/src/Syroot.Worms.Mgame.GameServer/Client.WorldPartyAqua.cs +++ b/src/Syroot.Worms.Mgame.GameServer/Client.WorldPartyAqua.cs @@ -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() }); + } + + public void HandleWwpaDisconnectQuery(DisconnectQuery packet) { } } } diff --git a/src/Syroot.Worms.Mgame.GameServer/Client.cs b/src/Syroot.Worms.Mgame.GameServer/Client.cs index 54a759e..5540acb 100644 --- a/src/Syroot.Worms.Mgame.GameServer/Client.cs +++ b/src/Syroot.Worms.Mgame.GameServer/Client.cs @@ -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)}"; } -} \ No newline at end of file +} diff --git a/src/Syroot.Worms.Mgame.GameServer/Core/IO/SpanReaderExtensions.cs b/src/Syroot.Worms.Mgame.GameServer/Core/IO/SpanReaderExtensions.cs new file mode 100644 index 0000000..58d5a59 --- /dev/null +++ b/src/Syroot.Worms.Mgame.GameServer/Core/IO/SpanReaderExtensions.cs @@ -0,0 +1,19 @@ +using Syroot.BinaryData.Memory; + +namespace Syroot.Worms.Mgame.GameServer.Core.IO +{ + /// + /// Represents extension methods for instances. + /// + internal static class SpanReaderExtensions + { + // ---- METHODS (INTERNAL) ------------------------------------------------------------------------------------- + + /// + /// Reads the remaining bytes that are available. + /// + /// The extended instance. + /// The remaining bytes in the reader. + internal static byte[] ReadToEnd(this ref SpanReader self) => self.ReadBytes(self.Length - self.Position); + } +} diff --git a/src/Syroot.Worms.Mgame.GameServer/Core/IO/SpanWriterExtensions.cs b/src/Syroot.Worms.Mgame.GameServer/Core/IO/SpanWriterExtensions.cs index 695d24b..128a768 100644 --- a/src/Syroot.Worms.Mgame.GameServer/Core/IO/SpanWriterExtensions.cs +++ b/src/Syroot.Worms.Mgame.GameServer/Core/IO/SpanWriterExtensions.cs @@ -15,7 +15,7 @@ namespace Syroot.Worms.Mgame.GameServer.Core.IO /// /// The extended instance. /// The to write. - 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); diff --git a/src/Syroot.Worms.Mgame.GameServer/Packets/AppConnection.cs b/src/Syroot.Worms.Mgame.GameServer/Packets/AppConnection.cs index 99ba478..bc85b09 100644 --- a/src/Syroot.Worms.Mgame.GameServer/Packets/AppConnection.cs +++ b/src/Syroot.Worms.Mgame.GameServer/Packets/AppConnection.cs @@ -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 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 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); } } diff --git a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelConnectQuery.cs b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelConnectQuery.cs index 6a781c4..ed1fd53 100644 --- a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelConnectQuery.cs +++ b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelConnectQuery.cs @@ -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 { @@ -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 diff --git a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelConnectReply.cs b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelConnectReply.cs index 9cd3adb..e2c2b1b 100644 --- a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelConnectReply.cs +++ b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelConnectReply.cs @@ -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) { diff --git a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelEnterFinishReply.cs b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelEnterFinishReply.cs index 48c5e54..1290436 100644 --- a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelEnterFinishReply.cs +++ b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelEnterFinishReply.cs @@ -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) { } } } diff --git a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelEnterQuery.cs b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelEnterQuery.cs index 1d270df..d2cdd9f 100644 --- a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelEnterQuery.cs +++ b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelEnterQuery.cs @@ -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(); } } diff --git a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelEnterReply.cs b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelEnterReply.cs index c3b08eb..00e1fb1 100644 --- a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelEnterReply.cs +++ b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelEnterReply.cs @@ -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); } } diff --git a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelInfosReply.cs b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelListReply.cs similarity index 92% rename from src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelInfosReply.cs rename to src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelListReply.cs index 22635bd..55e0a34 100644 --- a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelInfosReply.cs +++ b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelListReply.cs @@ -11,7 +11,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms /// Represents an additional server response to a , providing available server channels. /// [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()); diff --git a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelTop20Query.cs b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelTop20Query.cs index 6168a0b..0fc03e8 100644 --- a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelTop20Query.cs +++ b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelTop20Query.cs @@ -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(); } } diff --git a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelTop20Reply.cs b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelTop20Reply.cs index 8a768c2..24f1466 100644 --- a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelTop20Reply.cs +++ b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ChannelTop20Reply.cs @@ -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) diff --git a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ConnectQuery.cs b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ConnectQuery.cs index 2f4a968..60d4185 100644 --- a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ConnectQuery.cs +++ b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ConnectQuery.cs @@ -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(); } } diff --git a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ConnectReply.cs b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ConnectReply.cs index 0747f41..367fdd6 100644 --- a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ConnectReply.cs +++ b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ConnectReply.cs @@ -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); } } diff --git a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/LoginQuery.cs b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/LoginQuery.cs index 1122efd..c6b62d7 100644 --- a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/LoginQuery.cs +++ b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/LoginQuery.cs @@ -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 diff --git a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/LoginReply.cs b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/LoginReply.cs index fd733e1..157b279 100644 --- a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/LoginReply.cs +++ b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/LoginReply.cs @@ -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); } } diff --git a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ServerInfoReply.cs b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ServerInfoReply.cs index 2de1c80..efaca99 100644 --- a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ServerInfoReply.cs +++ b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/ServerInfoReply.cs @@ -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")); } } } diff --git a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/StartSingleGameQuery.cs b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/StartSingleGameQuery.cs index bb489e8..284b7ae 100644 --- a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/StartSingleGameQuery.cs +++ b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/StartSingleGameQuery.cs @@ -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(); 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 diff --git a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/StartSingleGameReply.cs b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/StartSingleGameReply.cs index 058b65f..ea47cc2 100644 --- a/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/StartSingleGameReply.cs +++ b/src/Syroot.Worms.Mgame.GameServer/Packets/OnlineWorms/StartSingleGameReply.cs @@ -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); } diff --git a/src/Syroot.Worms.Mgame.GameServer/Packets/Packet.cs b/src/Syroot.Worms.Mgame.GameServer/Packets/Packet.cs index 7ef1986..c1d1c4b 100644 --- a/src/Syroot.Worms.Mgame.GameServer/Packets/Packet.cs +++ b/src/Syroot.Worms.Mgame.GameServer/Packets/Packet.cs @@ -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); } } diff --git a/src/Syroot.Worms.Mgame.GameServer/Packets/RawPacket.cs b/src/Syroot.Worms.Mgame.GameServer/Packets/RawPacket.cs index d7c5d69..dd10e57 100644 --- a/src/Syroot.Worms.Mgame.GameServer/Packets/RawPacket.cs +++ b/src/Syroot.Worms.Mgame.GameServer/Packets/RawPacket.cs @@ -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 diff --git a/src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/ChannelListQuery.cs b/src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/ChannelListQuery.cs new file mode 100644 index 0000000..68ad04c --- /dev/null +++ b/src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/ChannelListQuery.cs @@ -0,0 +1,17 @@ +using Syroot.BinaryData.Memory; + +namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua +{ + /// + /// Represents the client request for a . + /// + [Packet(PacketFormat.Wwpa, 0x801E)] + internal class ChannelListQuery : Packet + { + // ---- METHODS (INTERNAL) ------------------------------------------------------------------------------------- + + internal override void Load(ref SpanReader reader) { } + + internal override void Save(ref SpanWriter writer) { } + } +} diff --git a/src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/ChannelListReply.cs b/src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/ChannelListReply.cs new file mode 100644 index 0000000..128264b --- /dev/null +++ b/src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/ChannelListReply.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using Syroot.BinaryData.Memory; + +namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua +{ + /// + /// Represents the server reply to a . + /// + [Packet(PacketFormat.Wwpa, 0x801F)] + internal class ChannelListReply : Packet + { + // ---- PROPERTIES --------------------------------------------------------------------------------------------- + + public IList 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 + { + } +} diff --git a/src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/ConnectQuery.cs b/src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/ConnectQuery.cs index c431138..391c2ac 100644 --- a/src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/ConnectQuery.cs +++ b/src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/ConnectQuery.cs @@ -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) { } } } diff --git a/src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/ConnectReply.cs b/src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/ConnectReply.cs new file mode 100644 index 0000000..776770d --- /dev/null +++ b/src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/ConnectReply.cs @@ -0,0 +1,39 @@ +using System; +using Syroot.BinaryData.Memory; + +namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua +{ + /// + /// Represents the server response to a . + /// + [Packet(PacketFormat.Wwpa, 0x8002)] + internal class ConnectReply : Packet + { + // ---- PROPERTIES --------------------------------------------------------------------------------------------- + + /// + /// Gets or sets an error message displayed to prevent the connection attempt. This property must be + /// to allow further communication. + /// + internal string ErrorMessage { get; set; } + + /// + /// Gets or sets the server version reported to the client, and checked by it to allow further communication. + /// + 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); + } + } +} diff --git a/src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/DisconnectQuery.cs b/src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/DisconnectQuery.cs new file mode 100644 index 0000000..a31bb4f --- /dev/null +++ b/src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/DisconnectQuery.cs @@ -0,0 +1,17 @@ +using Syroot.BinaryData.Memory; + +namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua +{ + /// + /// Represents the client packet probably sent when it notifies about disconnecting. + /// + [Packet(PacketFormat.Wwpa, 0x801B)] + internal class DisconnectQuery : Packet + { + // ---- METHODS (INTERNAL) ------------------------------------------------------------------------------------- + + internal override void Load(ref SpanReader reader) { } + + internal override void Save(ref SpanWriter writer) { } + } +} diff --git a/src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/LoginQuery.cs b/src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/LoginQuery.cs new file mode 100644 index 0000000..4c551b5 --- /dev/null +++ b/src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/LoginQuery.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using Syroot.BinaryData.Memory; + +namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua +{ + /// + /// Represents the client request for a . + /// + [Packet(PacketFormat.Wwpa, 0x8019)] + internal class LoginQuery : Packet + { + // ---- PROPERTIES --------------------------------------------------------------------------------------------- + + /// + /// Gets or sets the names and passwords of the players to login. + /// + public IList Logins { get; set; } + + // ---- METHODS (INTERNAL) ------------------------------------------------------------------------------------- + + internal override void Load(ref SpanReader reader) + { + Logins = new List { 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 + { + /// + /// Gets or sets the name of the player to login. + /// + internal string UserName { get; set; } + + /// + /// Gets or sets the password with which the player profile is authenticated. + /// + internal string Password { get; set; } + } +} diff --git a/src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/LoginReply.cs b/src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/LoginReply.cs new file mode 100644 index 0000000..b547ce7 --- /dev/null +++ b/src/Syroot.Worms.Mgame.GameServer/Packets/WorldPartyAqua/LoginReply.cs @@ -0,0 +1,43 @@ +using System; +using Syroot.BinaryData.Memory; + +namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua +{ + /// + /// Represents the server response to a . + /// + [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 + } +} diff --git a/src/Syroot.Worms.Mgame.GameServer/ServerConfig.json b/src/Syroot.Worms.Mgame.GameServer/ServerConfig.json index 72237f0..7710161 100644 --- a/src/Syroot.Worms.Mgame.GameServer/ServerConfig.json +++ b/src/Syroot.Worms.Mgame.GameServer/ServerConfig.json @@ -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) diff --git a/src/Syroot.Worms.Mgame/Encodings.cs b/src/Syroot.Worms.Mgame/Encodings.cs index 0c80ce9..077ad70 100644 --- a/src/Syroot.Worms.Mgame/Encodings.cs +++ b/src/Syroot.Worms.Mgame/Encodings.cs @@ -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 } } } diff --git a/src/Syroot.Worms.Mgame/LaunchConfig.cs b/src/Syroot.Worms.Mgame/LaunchConfig.cs index b5cf698..441b15d 100644 --- a/src/Syroot.Worms.Mgame/LaunchConfig.cs +++ b/src/Syroot.Worms.Mgame/LaunchConfig.cs @@ -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); diff --git a/src/Syroot.Worms.Mgame/Lpd.cs b/src/Syroot.Worms.Mgame/Lpd.cs index 2163c1c..6639160 100644 --- a/src/Syroot.Worms.Mgame/Lpd.cs +++ b/src/Syroot.Worms.Mgame/Lpd.cs @@ -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() diff --git a/src/Syroot.Worms.Mgame/PasswordCrypto.cs b/src/Syroot.Worms.Mgame/PasswordCrypto.cs index 5e1e41e..154d0c5 100644 --- a/src/Syroot.Worms.Mgame/PasswordCrypto.cs +++ b/src/Syroot.Worms.Mgame/PasswordCrypto.cs @@ -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); } } }