Implement ChannelCmdPacket.

This commit is contained in:
Ray Koopa 2019-01-20 00:14:22 +01:00
parent b527021df4
commit 441648da6a
36 changed files with 367 additions and 132 deletions

View File

@ -93,9 +93,41 @@ namespace Syroot.Worms.Mgame.GameServer
public void HandleWwpaChannelConnect(ChannelLoginQuery packet)
{
SendPacket(new ChannelLoginReply());
}
public void HandleWwpaChannelCmd(ChannelCmdQuery packet)
{
switch (packet.Data)
{
case StartSingleGameQueryData startSingleGameQuery:
HandleWwpaStartGameQuery(startSingleGameQuery);
break;
}
}
public void HandleWwpaDisconnectQuery(DisconnectQuery packet) { }
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
// ---- ChannelCmds ----
private void HandleWwpaStartGameQuery(StartSingleGameQueryData data)
{
SendPacket(new ChannelCmdReply(new StartSingleGameReplyData
{
Stuff = new List<StartSingleGameReplyStuff>
{
new StartSingleGameReplyStuff
{
UnknownA = 1,
UnknownB = 2,
UnknownC = 3,
UnknownD = 4,
UnknownE = 5
}
}
}));
}
}
}

View File

@ -43,7 +43,7 @@ namespace Syroot.Worms.Mgame.GameServer
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
private string FormatPacket(Packet packet, string direction)
private string FormatPacket(IPacket packet, string direction)
=> $"{TcpClient.Client.RemoteEndPoint} {direction} {packet.GetType().Name}{ObjectDumper.Dump(packet)}";
}
}

View File

@ -9,7 +9,7 @@ using Syroot.Worms.Mgame.GameServer.Core.Reflection;
namespace Syroot.Worms.Mgame.GameServer.Packets
{
/// <summary>
/// Represents a class capable of dispatching received <see cref="Packet"/> instances to a corresponding method.
/// Represents a class capable of dispatching received <see cref="IPacket"/> instances to a corresponding method.
/// </summary>
internal class AppConnection : IDisposable
{
@ -23,7 +23,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
// ---- FIELDS -------------------------------------------------------------------------------------------------
private readonly MethodHandler<Packet> _methodHandler;
private readonly MethodHandler<IPacket> _methodHandler;
private readonly SafeNetworkStream _tcpStream;
private bool _disposed;
@ -36,15 +36,15 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
/// <param name="tcpClient">The <see cref="System.Net.Sockets.TcpClient"/> to communicate with.</param>
internal AppConnection(TcpClient tcpClient)
{
_methodHandler = new MethodHandler<Packet>(this);
_methodHandler = new MethodHandler<IPacket>(this);
TcpClient = tcpClient;
_tcpStream = TcpClient.GetSafeStream();
}
// ---- EVENTS -------------------------------------------------------------------------------------------------
protected event EventHandler<Packet> PrePacketHandle;
protected event EventHandler<Packet> PrePacketSend;
protected event EventHandler<IPacket> PrePacketHandle;
protected event EventHandler<IPacket> PrePacketSend;
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
@ -68,7 +68,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
/// </summary>
internal void Listen()
{
Packet packet;
IPacket packet;
while ((packet = ReceivePacket()) != null)
{
PrePacketHandle?.Invoke(this, packet);
@ -88,7 +88,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
}
}
protected bool SendPacket(Packet packet)
protected bool SendPacket(IPacket packet)
{
PrePacketSend?.Invoke(this, packet);
try
@ -117,7 +117,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
private Packet ReceivePacket()
private IPacket ReceivePacket()
{
try
{
@ -137,7 +137,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
catch (ObjectDisposedException) { return null; } // The underlying stream closed.
}
private Packet ReceiveOWChannelPacket()
private IPacket ReceiveOWChannelPacket()
{
// Read head.
if (_tcpStream.Read1Byte() != 1)
@ -152,12 +152,12 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
throw new IOException("Invalid OW channel packet end tag.");
// Instantiate, deserialize, and return packet.
Packet packet = PacketFactory.Create(PacketFormat.OWChannel, id);
IPacket packet = PacketFactory.Create(PacketFormat.OWChannel, id);
packet.Load(ref reader);
return packet;
}
private Packet ReceiveOWServerPacket(int tag)
private IPacket ReceiveOWServerPacket(int tag)
{
// Read head.
int dataSize = _tcpStream.ReadUInt16();
@ -165,12 +165,12 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
SpanReader reader = new SpanReader(_tcpStream.ReadBytes(dataSize), encoding: Encodings.Korean);
// Instantiate, deserialize, and return packet.
Packet packet = PacketFactory.Create(PacketFormat.OWServer, tag);
IPacket packet = PacketFactory.Create(PacketFormat.OWServer, tag);
packet.Load(ref reader);
return packet;
}
private Packet ReceiveWwpaPacket()
private IPacket ReceiveWwpaPacket()
{
// Read head.
if (!_tcpStream.ReadBoolean())
@ -193,13 +193,13 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
// Instantiate, deserialize, and return packet.
SpanReader reader = new SpanReader(PacketCompression.Decompress(compressedData), encoding: Encodings.Korean);
int id = reader.ReadInt32();
Packet packet = PacketFactory.Create(PacketFormat.Wwpa, id);
IPacket packet = PacketFactory.Create(PacketFormat.Wwpa, id);
SpanReader dataReader = reader.Slice();
packet.Load(ref dataReader);
return packet;
}
private void SendOWChannelPacket(int id, Packet packet)
private void SendOWChannelPacket(int id, IPacket packet)
{
// Retrieve data. Must have at least 1 byte.
SpanWriter writer = new SpanWriter(new byte[_maxDataSize], encoding: Encodings.Korean);
@ -219,7 +219,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
_tcpStream.WriteUInt16(_owTagEndChannel);
}
private void SendOWServerPacket(int id, Packet packet)
private void SendOWServerPacket(int id, IPacket packet)
{
// Retrieve data.
SpanWriter writer = new SpanWriter(new byte[_maxDataSize], encoding: Encodings.Korean);
@ -233,7 +233,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
_tcpStream.Write(writer.Span);
}
private void SendWwpaPacket(int id, Packet packet, bool compress)
private void SendWwpaPacket(int id, IPacket packet, bool compress)
{
// Retrieve (decompressed) data.
SpanWriter writer = new SpanWriter(new byte[_maxDataSize], encoding: Encodings.Korean);

View File

@ -8,12 +8,12 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
/// to the channel screen (game lobby).
/// </summary>
[Packet(PacketFormat.OWChannel, 0x44)]
internal class ChannelEnterFinishReply : Packet
internal class ChannelEnterFinishReply : IPacket
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader) => throw new NotImplementedException();
public void Load(ref SpanReader reader) => throw new NotImplementedException();
internal override void Save(ref SpanWriter writer) { }
public void Save(ref SpanWriter writer) { }
}
}

View File

@ -8,7 +8,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
/// Represents the client request for a <see cref="ChannelEnterReply"/>.
/// </summary>
[Packet(PacketFormat.OWServer, 0x8034)]
internal class ChannelEnterQuery : Packet
internal class ChannelEnterQuery : IPacket
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
@ -16,14 +16,14 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
public IPEndPoint ChannelEndPoint { get; set; }
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader)
public void Load(ref SpanReader reader)
{
PlayerID = reader.ReadString2();
ChannelEndPoint = new IPEndPoint(IPAddress.Parse(reader.ReadString2()), reader.ReadUInt16());
}
internal override void Save(ref SpanWriter writer) => throw new NotImplementedException();
public void Save(ref SpanWriter writer) => throw new NotImplementedException();
}
}

View File

@ -8,7 +8,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
/// Represents the server response to a <see cref="ChannelEnterQuery"/>.
/// </summary>
[Packet(PacketFormat.OWServer, 0x8035)]
internal class ChannelEnterReply : Packet
internal class ChannelEnterReply : IPacket
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
@ -17,11 +17,11 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
/// </summary>
public IPEndPoint EndPoint { get; set; }
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader) => throw new NotImplementedException();
public void Load(ref SpanReader reader) => throw new NotImplementedException();
internal override void Save(ref SpanWriter writer)
public void Save(ref SpanWriter writer)
{
writer.WriteString2(EndPoint.Address.ToString());
writer.WriteUInt16((ushort)EndPoint.Port);

View File

@ -11,17 +11,17 @@ 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 ChannelListReply : Packet
internal class ChannelListReply : IPacket
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
public IList<ChannelInfo> Channels { get; set; }
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader) => throw new NotImplementedException();
public void Load(ref SpanReader reader) => throw new NotImplementedException();
internal override void Save(ref SpanWriter writer)
public void Save(ref SpanWriter writer)
{
writer.WriteUInt16((ushort)Channels.Count);
foreach (ChannelInfo channel in Channels)

View File

@ -10,7 +10,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
/// Represents the client request for a <see cref="ChannelLoginReply"/>.
/// </summary>
[Packet(PacketFormat.OWChannel, 0x10)]
internal class ChannelLoginQuery : Packet
internal class ChannelLoginQuery : IPacket
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
@ -24,9 +24,9 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
public byte UnknownB { get; set; }
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader)
public void Load(ref SpanReader reader)
{
Players = new List<PlayerCredentials>
{
@ -52,6 +52,6 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
UnknownB = reader.ReadByte();
}
internal override void Save(ref SpanWriter writer) => throw new NotImplementedException();
public void Save(ref SpanWriter writer) => throw new NotImplementedException();
}
}

View File

@ -7,7 +7,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
/// Represents the server response to a <see cref="ChannelLoginQuery"/>.
/// </summary>
[Packet(PacketFormat.OWChannel, 0x11)]
internal class ChannelLoginReply : Packet
internal class ChannelLoginReply : IPacket
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
@ -15,11 +15,11 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
public ChannelConnectPlayerInfo Player { get; set; }
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader) => throw new NotImplementedException();
public void Load(ref SpanReader reader) => throw new NotImplementedException();
internal override void Save(ref SpanWriter writer)
public void Save(ref SpanWriter writer)
{
if (Result == ChannelConnectResult.Success)
{

View File

@ -7,7 +7,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
/// Represents the client request for a <see cref="ChannelLoginReply"/>.
/// </summary>
[Packet(PacketFormat.OWChannel, 0x37)]
internal class ChannelTop20Query : Packet
internal class ChannelTop20Query : IPacket
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
@ -16,13 +16,13 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
/// </summary>
public ushort Count { get; set; }
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader)
public void Load(ref SpanReader reader)
{
Count = reader.ReadUInt16();
}
internal override void Save(ref SpanWriter writer) => throw new NotImplementedException();
public void Save(ref SpanWriter writer) => throw new NotImplementedException();
}
}

View File

@ -8,7 +8,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
/// Represents the server response to a <see cref="ChannelTop20Query"/>.
/// </summary>
[Packet(PacketFormat.OWChannel, 0x36)]
internal class ChannelTop20Reply : Packet
internal class ChannelTop20Reply : IPacket
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
@ -16,11 +16,11 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
public IList<ChannelTop20Player> Top20 { get; set; } // 20 elements.
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader) => throw new NotImplementedException();
public void Load(ref SpanReader reader) => throw new NotImplementedException();
internal override void Save(ref SpanWriter writer)
public void Save(ref SpanWriter writer)
{
writer.WriteStringFix(UnknownA, 30);
foreach (ChannelTop20Player top20Player in Top20)

View File

@ -7,12 +7,12 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
/// Represents the client request for a <see cref="ConnectReply"/>.
/// </summary>
[Packet(PacketFormat.OWServer, 0x800E)]
internal class ConnectQuery : Packet
internal class ConnectQuery : IPacket
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader) { }
public void Load(ref SpanReader reader) { }
internal override void Save(ref SpanWriter writer) => throw new NotImplementedException();
public void Save(ref SpanWriter writer) => throw new NotImplementedException();
}
}

View File

@ -7,7 +7,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
/// Represents the server response to a <see cref="ConnectQuery"/>.
/// </summary>
[Packet(PacketFormat.OWServer, 0x800F)]
internal class ConnectReply : Packet
internal class ConnectReply : IPacket
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
@ -17,11 +17,11 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
internal ushort Version { get; set; }
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader) => throw new NotImplementedException();
public void Load(ref SpanReader reader) => throw new NotImplementedException();
internal override void Save(ref SpanWriter writer)
public void Save(ref SpanWriter writer)
{
writer.WriteString2(Unknown);
writer.WriteByte(0);

View File

@ -9,7 +9,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
/// Represents the client request for a <see cref="LoginReply"/>.
/// </summary>
[Packet(PacketFormat.OWServer, 0x8000)]
internal class LoginQuery : Packet
internal class LoginQuery : IPacket
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
@ -19,9 +19,9 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
internal IPAddress ClientIP { get; set; }
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader)
public void Load(ref SpanReader reader)
{
Unknown1 = reader.ReadUInt16();
Players = new PlayerCredentials[reader.ReadUInt16()];
@ -30,6 +30,6 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
ClientIP = IPAddress.Parse(reader.ReadString2());
}
internal override void Save(ref SpanWriter writer) => throw new NotImplementedException();
public void Save(ref SpanWriter writer) => throw new NotImplementedException();
}
}

View File

@ -7,7 +7,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
/// Represents the server response to a <see cref="LoginQuery"/>.
/// </summary>
[Packet(PacketFormat.OWServer, 0x8001)]
internal class LoginReply : Packet
internal class LoginReply : IPacket
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
@ -21,11 +21,11 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
internal LoginPlayerInfo[] PlayerInfos { get; set; }
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader) => throw new NotImplementedException();
public void Load(ref SpanReader reader) => throw new NotImplementedException();
internal override void Save(ref SpanWriter writer)
public void Save(ref SpanWriter writer)
{
bool loginSuccessful = Result == LoginResult.Success;
writer.WriteBoolean(loginSuccessful);

View File

@ -8,7 +8,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
/// screen text.
/// </summary>
[Packet(PacketFormat.OWServer, 0x8033)]
internal class ServerInfoReply : Packet
internal class ServerInfoReply : IPacket
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
@ -17,11 +17,11 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
/// </summary>
internal string Text { get; set; }
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader) => throw new NotImplementedException();
public void Load(ref SpanReader reader) => throw new NotImplementedException();
internal override void Save(ref SpanWriter writer)
public void Save(ref SpanWriter writer)
{
writer.WriteString2(Text.Replace(Environment.NewLine, "\n"));
}

View File

@ -7,7 +7,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
/// Represents the client request for a <see cref="StartSingleGameReply"/>.
/// </summary>
[Packet(PacketFormat.OWChannel, 0x38)]
internal class StartSingleGameQuery : Packet
internal class StartSingleGameQuery : IPacket
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
@ -15,16 +15,16 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
public byte UnknownB { get; set; }
public byte UnknownC { get; set; } // 0x3D on first round, 0x3E on any other
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader)
public void Load(ref SpanReader reader)
{
RoundType = reader.ReadEnumSafe<GameStartRoundType>();
UnknownB = reader.ReadByte();
UnknownC = reader.ReadByte();
}
internal override void Save(ref SpanWriter writer) => throw new NotImplementedException();
public void Save(ref SpanWriter writer) => throw new NotImplementedException();
}
internal enum GameStartRoundType : byte

View File

@ -7,17 +7,17 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
/// Represents the server response to a <see cref="StartSingleGameQuery"/>.
/// </summary>
[Packet(PacketFormat.OWChannel, 0x39)]
internal class StartSingleGameReply : Packet
internal class StartSingleGameReply : IPacket
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
public bool Success { get; set; } = true;
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader) => throw new NotImplementedException();
public void Load(ref SpanReader reader) => throw new NotImplementedException();
internal override void Save(ref SpanWriter writer)
public void Save(ref SpanWriter writer)
{
writer.WriteBoolean2(Success);
}

View File

@ -6,12 +6,12 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
/// Represents a packet with an ID specifying its contents. To allow the server to instantiate child packet classes,
/// decorate it with the <see cref="PacketAttribute"/>.
/// </summary>
internal abstract class Packet
internal interface IPacket
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
// ---- METHODS ------------------------------------------------------------------------------------------------
internal abstract void Load(ref SpanReader reader);
void Load(ref SpanReader reader);
internal abstract void Save(ref SpanWriter writer);
void Save(ref SpanWriter writer);
}
}

View File

@ -3,7 +3,7 @@
namespace Syroot.Worms.Mgame.GameServer.Packets
{
/// <summary>
/// Decorates a <see cref="Packet"/> child class with the ID of the packet it represents.
/// Decorates a <see cref="IPacket"/> child class with the ID of the packet it represents.
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
internal class PacketAttribute : Attribute

View File

@ -6,7 +6,7 @@ using System.Reflection;
namespace Syroot.Worms.Mgame.GameServer.Packets
{
/// <summary>
/// Represents a factory creating <see cref="Packet"/> instances by mapping their ID to types to instantiate.
/// Represents a factory creating <see cref="IPacket"/> instances by mapping their ID to types to instantiate.
/// </summary>
internal static class PacketFactory
{
@ -37,31 +37,32 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
/// <summary>
/// Creates a new <see cref="Packet"/> instance mapped to the given <paramref name="id"/>.
/// Creates a new <see cref="IPacket"/> instance mapped to the given <paramref name="id"/>.
/// </summary>
/// <param name="format">The <see cref="PacketFormat"/> to instantiate.</param>
/// <param name="id">The ID of the packet class to instantiate.</param>
/// <returns>The created <see cref="Packet"/> instance.</returns>
/// <returns>The created <see cref="IPacket"/> instance.</returns>
/// <exception cref="KeyNotFoundException">No class was mapped to the given packet ID.</exception>
internal static Packet Create(PacketFormat type, int id)
internal static IPacket Create(PacketFormat format, int id)
{
foreach (KeyValuePair<PacketAttribute, Type> packetMeta in _packetCache)
{
if (packetMeta.Key.Format == type && packetMeta.Key.ID == id)
return (Packet)Activator.CreateInstance(packetMeta.Value, true);
if (packetMeta.Key.ID == id)
return (IPacket)Activator.CreateInstance(packetMeta.Value, true);
}
// No packet metadata matching.
#if DEBUG
return new RawPacket(type, id);
return new RawPacket(format, id);
#endif
throw new ArgumentException($"{type} packet with ID {id} could not be created.");
throw new ArgumentException($"{format} packet with ID {id} could not be created.");
}
/// <summary>
/// Gets the <see cref="PacketAttribute"/> metadata for the class of the given <paramref name="packet"/>.
/// </summary>
/// <param name="packet">The <see cref="Packet"/> whose metadata will be returned.</param>
/// <param name="packet">The <see cref="IPacket"/> whose metadata will be returned.</param>
/// <returns>The metadata of the packet class.</returns>
internal static PacketAttribute GetAttribute(Packet packet)
internal static PacketAttribute GetAttribute(IPacket packet)
{
#if DEBUG
if (packet is RawPacket rawPacket)

View File

@ -6,7 +6,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
/// <summary>
/// Represents a special fallback packet which simply stores any ID and the raw packet data.
/// </summary>
internal class RawPacket : Packet
internal class RawPacket : IPacket
{
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
@ -27,9 +27,9 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader) => Data = reader.ReadBytes(reader.Length);
public void Load(ref SpanReader reader) => Data = reader.ReadBytes(reader.Length);
internal override void Save(ref SpanWriter writer) => writer.WriteBytes(Data);
public void Save(ref SpanWriter writer) => writer.WriteBytes(Data);
}
}
#endif

View File

@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Syroot.BinaryData.Memory;
using Syroot.Worms.Mgame.GameServer.Core.IO;
namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
{
// TODO: Ugly, but requires bigger redesign to allow a second identifier in the packets.
/// <summary>
/// Represents the base class for <see cref="ChannelCmdQuery"/> and <see cref="ChannelCmdReply"/> packets.
/// </summary>
internal abstract class ChannelCmdPacket : IPacket
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
public IChannelCmdData Data { get; set; }
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
public void Load(ref SpanReader reader)
{
ChannelCmd cmd = reader.ReadEnum<ChannelCmd>();
Data = GetDataClasses().TryGetValue(cmd, out Type type)
? (IChannelCmdData)Activator.CreateInstance(type)
: new RawChannelCmdData(cmd);
Data.Load(ref reader);
}
public void Save(ref SpanWriter writer)
{
ChannelCmd cmd;
switch (Data)
{
case RawChannelCmdData rawChannelCmdData:
cmd = rawChannelCmdData.Cmd;
break;
default:
Type dataType = Data.GetType();
cmd = GetDataClasses().First(x => x.Value == dataType).Key;
break;
}
writer.WriteEnum(cmd);
Data.Save(ref writer);
}
// ---- METHODS (PROTECTED) ------------------------------------------------------------------------------------
protected abstract IDictionary<ChannelCmd, Type> GetDataClasses();
}
internal enum ChannelCmd : int
{
StartSingleGameQuery = 5
}
internal interface IChannelCmdData
{
void Load(ref SpanReader reader);
void Save(ref SpanWriter writer);
}
internal class RawChannelCmdData : IChannelCmdData
{
public RawChannelCmdData(ChannelCmd cmd) => Cmd = cmd;
internal ChannelCmd Cmd { get; }
internal byte[] Data { get; set; }
public void Load(ref SpanReader reader) => Data = reader.ReadToEnd();
public void Save(ref SpanWriter writer) => writer.WriteBytes(Data);
}
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
{
/// <summary>
/// Represents the client request for a <see cref="ChannelCmdReply"/>.
/// </summary>
[Packet(PacketFormat.Wwpa, 0x10A)]
internal class ChannelCmdQuery : ChannelCmdPacket
{
// ---- FIELDS -------------------------------------------------------------------------------------------------
private static readonly Dictionary<ChannelCmd, Type> _queryClasses = new Dictionary<ChannelCmd, Type>
{
[ChannelCmd.StartSingleGameQuery] = typeof(StartSingleGameQueryData)
};
// ---- METHODS (PROTECTED) ------------------------------------------------------------------------------------
protected override IDictionary<ChannelCmd, Type> GetDataClasses() => _queryClasses;
}
}

View File

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
{
/// <summary>
/// Represents the server response to a <see cref="ChannelCmdQuery"/>.
/// </summary>
[Packet(PacketFormat.Wwpa, 0x10B)]
internal class ChannelCmdReply : ChannelCmdPacket
{
// ---- FIELDS -------------------------------------------------------------------------------------------------
private static readonly Dictionary<ChannelCmd, Type> _replyClasses = new Dictionary<ChannelCmd, Type>
{
[ChannelCmd.StartSingleGameQuery] = typeof(StartSingleGameReplyData)
};
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
internal ChannelCmdReply(IChannelCmdData data)
{
Data = data;
}
// ---- METHODS (PROTECTED) ------------------------------------------------------------------------------------
protected override IDictionary<ChannelCmd, Type> GetDataClasses() => _replyClasses;
}
}

View File

@ -6,12 +6,12 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
/// Represents the client request for a <see cref="ChannelListReply"/>.
/// </summary>
[Packet(PacketFormat.Wwpa, 0x801E)]
internal class ChannelListQuery : Packet
internal class ChannelListQuery : IPacket
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader) { }
public void Load(ref SpanReader reader) { }
internal override void Save(ref SpanWriter writer) { }
public void Save(ref SpanWriter writer) { }
}
}

View File

@ -11,23 +11,23 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
/// Represents the server reply to a <see cref="ChannelListQuery"/>.
/// </summary>
[Packet(PacketFormat.Wwpa, 0x801F)]
internal class ChannelListReply : Packet
internal class ChannelListReply : IPacket
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
public IList<ChannelInfo> Channels { get; set; }
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader) => throw new NotImplementedException();
public void Load(ref SpanReader reader) => throw new NotImplementedException();
internal override void Save(ref SpanWriter writer)
public void Save(ref SpanWriter writer)
{
writer.WriteUInt16((ushort)Channels.Count);
writer.WriteByte((byte)Channels.Count(x => x.Type == ChannelType.Normal));
writer.WriteByte((byte)Channels.Count(x => x.Type == ChannelType.Roping));
writer.WriteByte((byte)Channels.Count(x => x.Type == ChannelType.Guild));
writer.WriteByte((byte)Channels.Count(x => x.Type == ChannelType.Event));
writer.WriteByte((byte)Channels.Count(x => x.Type == ChannelType.Normal)); // index 0
writer.WriteByte((byte)Channels.Count(x => x.Type == ChannelType.Roping)); // index 3
writer.WriteByte((byte)Channels.Count(x => x.Type == ChannelType.Guild)); // index 1
writer.WriteByte((byte)Channels.Count(x => x.Type == ChannelType.Event)); // index 2
foreach (ChannelInfo channel in Channels)
{
writer.WriteUInt16(channel.UnknownA);

View File

@ -11,7 +11,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
/// Represents the client request for a <see cref="ChannelConnectReply"/>.
/// </summary>
[Packet(PacketFormat.Wwpa, 0x101)]
internal class ChannelLoginQuery : Packet
internal class ChannelLoginQuery : IPacket
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
@ -21,9 +21,9 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
public byte UnknownB { get; set; }
public byte[] Remain { get; set; }
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader)
public void Load(ref SpanReader reader)
{
IPAddress = IPAddress.Parse(reader.ReadString2());
Players = new List<PlayerCredentials> { reader.ReadCredentials() };
@ -34,6 +34,6 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
Remain = reader.ReadToEnd();
}
internal override void Save(ref SpanWriter writer) => throw new NotImplementedException();
public void Save(ref SpanWriter writer) => throw new NotImplementedException();
}
}

View File

@ -0,0 +1,17 @@
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
{
/// <summary>
/// Represents the server response to a <see cref="ChannelConnectQuery"/>.
/// </summary>
[Packet(PacketFormat.Wwpa, 0x145)]
internal class ChannelLoginReply : IPacket
{
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
public void Load(ref SpanReader reader) { }
public void Save(ref SpanWriter writer) { }
}
}

View File

@ -6,12 +6,12 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
/// Represents the client request for a <see cref="ConnectReply"/>.
/// </summary>
[Packet(PacketFormat.Wwpa, 0x8001)]
internal class ConnectQuery : Packet
internal class ConnectQuery : IPacket
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader) { }
public void Load(ref SpanReader reader) { }
internal override void Save(ref SpanWriter writer) { }
public void Save(ref SpanWriter writer) { }
}
}

View File

@ -7,7 +7,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
/// Represents the server response to a <see cref="ConnectQuery"/>.
/// </summary>
[Packet(PacketFormat.Wwpa, 0x8002)]
internal class ConnectReply : Packet
internal class ConnectReply : IPacket
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
@ -22,11 +22,11 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
/// </summary>
internal ushort ServerVersion { get; set; }
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader) => throw new NotImplementedException();
public void Load(ref SpanReader reader) => throw new NotImplementedException();
internal override void Save(ref SpanWriter writer)
public void Save(ref SpanWriter writer)
{
bool connectionFailed = ErrorMessage != null;
writer.WriteBoolean4(connectionFailed);

View File

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

View File

@ -9,7 +9,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
/// Represents the client request for a <see cref="LoginReply"/>.
/// </summary>
[Packet(PacketFormat.Wwpa, 0x8019)]
internal class LoginQuery : Packet
internal class LoginQuery : IPacket
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
@ -18,15 +18,15 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
/// </summary>
public IList<PlayerCredentials> Players { get; set; }
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader)
public void Load(ref SpanReader reader)
{
Players = new List<PlayerCredentials> { reader.ReadCredentials() };
if (reader.ReadBoolean())
Players.Add(reader.ReadCredentials());
}
internal override void Save(ref SpanWriter writer) => throw new NotImplementedException();
public void Save(ref SpanWriter writer) => throw new NotImplementedException();
}
}

View File

@ -7,7 +7,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
/// Represents the server response to a <see cref="LoginQuery"/>.
/// </summary>
[Packet(PacketFormat.Wwpa, 0x801A)]
internal class LoginReply : Packet
internal class LoginReply : IPacket
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
@ -17,11 +17,11 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
public ushort UnknownB { get; set; }
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader) => throw new NotImplementedException();
public void Load(ref SpanReader reader) => throw new NotImplementedException();
internal override void Save(ref SpanWriter writer)
public void Save(ref SpanWriter writer)
{
writer.WriteEnumSafe(Result);
if (Result == LoginResult.Success)

View File

@ -0,0 +1,16 @@
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
{
/// <summary>
/// Represents the <see cref="ChannelCmdQuery"/> client request for a <see cref="StartSingleGameReplyData"/>.
/// </summary>
internal class StartSingleGameQueryData : IChannelCmdData
{
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
public void Load(ref SpanReader reader) { }
public void Save(ref SpanWriter writer) { }
}
}

View File

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
{
/// <summary>
/// Represents the <see cref="ChannelCmdQuery"/> server response to a <see cref="StartSingleGameQueryData"/>.
/// </summary>
internal class StartSingleGameReplyData : IChannelCmdData
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
public IList<StartSingleGameReplyStuff> Stuff { get; set; }
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
public void Load(ref SpanReader reader) => throw new NotImplementedException();
public void Save(ref SpanWriter writer)
{
writer.WriteUInt16((ushort)Stuff.Count);
foreach (StartSingleGameReplyStuff stuff in Stuff)
{
writer.WriteByte(stuff.UnknownA);
writer.WriteByte(stuff.UnknownB);
writer.WriteUInt16(stuff.UnknownC);
writer.WriteUInt16(stuff.UnknownD);
writer.WriteUInt16(stuff.UnknownE);
}
}
}
public class StartSingleGameReplyStuff
{
public byte UnknownA { get; set; }
public byte UnknownB { get; set; }
public ushort UnknownC { get; set; }
public ushort UnknownD { get; set; }
public ushort UnknownE { get; set; }
}
}