mirror of
https://gitlab.com/Syroot/Worms.git
synced 2025-01-27 22:27:58 +03:00
Dynamically implement channel commands.
This commit is contained in:
parent
a8073367f4
commit
38035742d6
@ -7,17 +7,30 @@ namespace Syroot.Worms.Mgame.GameServer
|
||||
{
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
public void HandleWwpaChannelCmd(CmdQuery packet)
|
||||
public void HandleWwpaChannelCmd(CmdStartSingleGameQuery packet)
|
||||
{
|
||||
switch (packet.Data)
|
||||
SendPacket(new CmdStartSingleGameReply
|
||||
{
|
||||
case StartSingleGameQueryData startSingleGame:
|
||||
HandleWwpaChannelCmdStartGame(startSingleGame);
|
||||
break;
|
||||
case Unknown6QueryData unknown6:
|
||||
HandleWwpaChannelCmdUnknown6(unknown6);
|
||||
break;
|
||||
}
|
||||
Stuff = new List<StartSingleGameReplyStuff>
|
||||
{
|
||||
new StartSingleGameReplyStuff
|
||||
{
|
||||
UnknownA = 1,
|
||||
UnknownB = 2,
|
||||
UnknownC = 3,
|
||||
UnknownD = 4,
|
||||
UnknownE = 5
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void HandleWwpaChannelCmd(CmdUnknown6Query packet)
|
||||
{
|
||||
SendPacket(new CmdUnknown6Reply
|
||||
{
|
||||
Result = Unknown6Status.Disconnect
|
||||
});
|
||||
}
|
||||
|
||||
public void HandleWwpaChannelDisconnect(DisconnectNotice packet) { }
|
||||
@ -56,35 +69,5 @@ namespace Syroot.Worms.Mgame.GameServer
|
||||
UnknownF = 0x55,
|
||||
});
|
||||
}
|
||||
|
||||
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
|
||||
|
||||
// ---- Cmds ----
|
||||
|
||||
private void HandleWwpaChannelCmdStartGame(StartSingleGameQueryData data)
|
||||
{
|
||||
SendPacket(new CmdReply(new StartSingleGameReplyData
|
||||
{
|
||||
Stuff = new List<StartSingleGameReplyStuff>
|
||||
{
|
||||
new StartSingleGameReplyStuff
|
||||
{
|
||||
UnknownA = 1,
|
||||
UnknownB = 2,
|
||||
UnknownC = 3,
|
||||
UnknownD = 4,
|
||||
UnknownE = 5
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private void HandleWwpaChannelCmdUnknown6(Unknown6QueryData unknown6)
|
||||
{
|
||||
SendPacket(new CmdReply(new Unknown6ReplyData
|
||||
{
|
||||
Result = Unknown6Status.Disconnect
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
|
||||
/// Decorates an <see cref="IPacket"/> child class with the ID of the OW channel packet it represents.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||
internal class OWChannelPacketAttribute : Attribute
|
||||
public class OWChannelPacketAttribute : Attribute
|
||||
{
|
||||
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
||||
|
||||
@ -15,7 +15,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
|
||||
/// ID of the packet it represents.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the packet which the decorated class represents.</param>
|
||||
internal OWChannelPacketAttribute(byte id)
|
||||
public OWChannelPacketAttribute(byte id)
|
||||
{
|
||||
ID = id;
|
||||
}
|
||||
@ -25,6 +25,6 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
|
||||
/// <summary>
|
||||
/// Gets the ID of the packet the decorated class represents.
|
||||
/// </summary>
|
||||
internal byte ID { get; }
|
||||
public byte ID { get; }
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
|
||||
/// Decorates an <see cref="IPacket"/> child class with the ID of the OW server packet it represents.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||
internal class OWServerPacketAttribute : Attribute
|
||||
public class OWServerPacketAttribute : Attribute
|
||||
{
|
||||
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
||||
|
||||
@ -15,7 +15,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
|
||||
/// ID of the packet it represents.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the packet which the decorated class represents.</param>
|
||||
internal OWServerPacketAttribute(ushort id)
|
||||
public OWServerPacketAttribute(ushort id)
|
||||
{
|
||||
ID = id;
|
||||
}
|
||||
@ -25,6 +25,6 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
|
||||
/// <summary>
|
||||
/// Gets the ID of the packet the decorated class represents.
|
||||
/// </summary>
|
||||
internal ushort ID { get; }
|
||||
public ushort ID { get; }
|
||||
}
|
||||
}
|
||||
|
@ -1,75 +0,0 @@
|
||||
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.Channel
|
||||
{
|
||||
// TODO: Ugly, but requires bigger redesign to allow a second identifier in the packets.
|
||||
|
||||
/// <summary>
|
||||
/// Represents the base class for <see cref="CmdQuery"/> and <see cref="CmdReply"/> packets.
|
||||
/// </summary>
|
||||
internal abstract class CmdPacket : IPacket
|
||||
{
|
||||
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||
|
||||
public ICmdData Data { get; set; }
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
public void Load(ref SpanReader reader)
|
||||
{
|
||||
Cmd cmd = reader.ReadEnum<Cmd>();
|
||||
Data = GetDataClasses().TryGetValue(cmd, out Type type)
|
||||
? (ICmdData)Activator.CreateInstance(type)
|
||||
: new RawCmdData(cmd);
|
||||
Data.Load(ref reader);
|
||||
}
|
||||
|
||||
public void Save(ref SpanWriter writer)
|
||||
{
|
||||
Cmd cmd;
|
||||
switch (Data)
|
||||
{
|
||||
case RawCmdData 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<Cmd, Type> GetDataClasses();
|
||||
}
|
||||
|
||||
internal enum Cmd : int
|
||||
{
|
||||
StartSingleGameQuery = 5,
|
||||
Unknown6 = 6
|
||||
}
|
||||
|
||||
internal interface ICmdData
|
||||
{
|
||||
void Load(ref SpanReader reader);
|
||||
void Save(ref SpanWriter writer);
|
||||
}
|
||||
|
||||
internal class RawCmdData : ICmdData
|
||||
{
|
||||
public RawCmdData(Cmd cmd) => Cmd = cmd;
|
||||
|
||||
internal Cmd 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);
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua.Channel
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the client request for a <see cref="CmdReply"/>.
|
||||
/// </summary>
|
||||
[WwpaPacket(0x10A)]
|
||||
internal class CmdQuery : CmdPacket
|
||||
{
|
||||
// ---- FIELDS -------------------------------------------------------------------------------------------------
|
||||
|
||||
private static readonly Dictionary<Cmd, Type> _queryClasses = new Dictionary<Cmd, Type>
|
||||
{
|
||||
[Cmd.StartSingleGameQuery] = typeof(StartSingleGameQueryData),
|
||||
[Cmd.Unknown6] = typeof(Unknown6QueryData)
|
||||
};
|
||||
|
||||
// ---- METHODS (PROTECTED) ------------------------------------------------------------------------------------
|
||||
|
||||
protected override IDictionary<Cmd, Type> GetDataClasses() => _queryClasses;
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua.Channel
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the server response to a <see cref="CmdQuery"/>.
|
||||
/// </summary>
|
||||
[WwpaPacket(0x10B)]
|
||||
internal class CmdReply : CmdPacket
|
||||
{
|
||||
// ---- FIELDS -------------------------------------------------------------------------------------------------
|
||||
|
||||
private static readonly Dictionary<Cmd, Type> _replyClasses = new Dictionary<Cmd, Type>
|
||||
{
|
||||
[Cmd.StartSingleGameQuery] = typeof(StartSingleGameReplyData),
|
||||
[Cmd.Unknown6] = typeof(Unknown6ReplyData)
|
||||
};
|
||||
|
||||
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
||||
|
||||
internal CmdReply(ICmdData data)
|
||||
{
|
||||
Data = data;
|
||||
}
|
||||
|
||||
// ---- METHODS (PROTECTED) ------------------------------------------------------------------------------------
|
||||
|
||||
protected override IDictionary<Cmd, Type> GetDataClasses() => _replyClasses;
|
||||
}
|
||||
}
|
@ -3,9 +3,10 @@
|
||||
namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua.Channel
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the <see cref="CmdQuery"/> client request for a <see cref="StartSingleGameReplyData"/>.
|
||||
/// Represents the <see cref="CmdQuery"/> client request for a <see cref="CmdStartSingleGameReply"/>.
|
||||
/// </summary>
|
||||
internal class StartSingleGameQueryData : ICmdData
|
||||
[WwpaPacket(0x10A, Command = 5)]
|
||||
internal class CmdStartSingleGameQuery : IPacket
|
||||
{
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
@ -5,9 +5,10 @@ using Syroot.BinaryData.Memory;
|
||||
namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua.Channel
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the <see cref="CmdQuery"/> server response to a <see cref="StartSingleGameQueryData"/>.
|
||||
/// Represents the <see cref="CmdQuery"/> server response to a <see cref="CmdStartSingleGameQuery"/>.
|
||||
/// </summary>
|
||||
internal class StartSingleGameReplyData : ICmdData
|
||||
[WwpaPacket(0x10B, Command = 5)]
|
||||
internal class CmdStartSingleGameReply : IPacket
|
||||
{
|
||||
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||
|
@ -4,9 +4,10 @@ using Syroot.BinaryData.Memory;
|
||||
namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua.Channel
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the <see cref="ChannelCmdQuery"/> client request for a <see cref="Unknown6ReplyData"/>.
|
||||
/// Represents the client request for a <see cref="CmdUnknown6Reply"/>.
|
||||
/// </summary>
|
||||
internal class Unknown6QueryData : ICmdData
|
||||
[WwpaPacket(0x10A, Command = 6)]
|
||||
internal class CmdUnknown6Query : IPacket
|
||||
{
|
||||
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||
|
@ -4,9 +4,10 @@ using Syroot.BinaryData.Memory;
|
||||
namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua.Channel
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the <see cref="CmdQuery"/> server response to a <see cref="Unknown6QueryData"/>.
|
||||
/// Represents the server response to a <see cref="CmdUnknown6Query"/>.
|
||||
/// </summary>
|
||||
internal class Unknown6ReplyData : ICmdData
|
||||
[WwpaPacket(0x10B, Command = 6)]
|
||||
internal class CmdUnknown6Reply : IPacket
|
||||
{
|
||||
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||
|
@ -6,7 +6,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
|
||||
/// Decorates an <see cref="IPacket"/> child class with the ID of the OW server packet it represents.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||
internal class WwpaPacketAttribute : Attribute
|
||||
public class WwpaPacketAttribute : Attribute
|
||||
{
|
||||
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
||||
|
||||
@ -15,7 +15,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
|
||||
/// the packet it represents.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the packet which the decorated class represents.</param>
|
||||
internal WwpaPacketAttribute(int id)
|
||||
public WwpaPacketAttribute(int id)
|
||||
{
|
||||
ID = id;
|
||||
}
|
||||
@ -25,11 +25,11 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
|
||||
/// <summary>
|
||||
/// Gets the ID of the packet the decorated class represents.
|
||||
/// </summary>
|
||||
internal int ID { get; }
|
||||
public int ID { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an optional command number which the packet represents.
|
||||
/// </summary>
|
||||
internal int Command { get; set; }
|
||||
public int Command { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,8 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
|
||||
|
||||
private const ushort _tagStart = 0x2E9E;
|
||||
private const ushort _tagEnd = 0x7F3F;
|
||||
private const int _channelCmdQueryID = 0x10A;
|
||||
private const int _channelCmdReplyID = 0x10B;
|
||||
private const int _maxDataSize = 1024;
|
||||
|
||||
// ---- FIELDS -------------------------------------------------------------------------------------------------
|
||||
@ -55,8 +57,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
|
||||
|
||||
// Instantiate, deserialize, and return packet.
|
||||
SpanReader reader = new SpanReader(PacketCompression.Decompress(compressedData), encoding: Encodings.Korean);
|
||||
int id = reader.ReadInt32();
|
||||
IPacket packet = GetPacket(id);
|
||||
IPacket packet = GetPacket(ref reader);
|
||||
if (packet == null)
|
||||
return null;
|
||||
SpanReader dataReader = reader.Slice();
|
||||
@ -66,13 +67,15 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
|
||||
|
||||
public bool TrySave(Stream stream, IPacket packet)
|
||||
{
|
||||
int? id = GetID(packet);
|
||||
if (!id.HasValue)
|
||||
WwpaPacketAttribute attrib = GetAttribute(packet);
|
||||
if (attrib == null)
|
||||
return false;
|
||||
|
||||
// Retrieve (decompressed) data.
|
||||
SpanWriter writer = new SpanWriter(new byte[_maxDataSize], encoding: Encodings.Korean);
|
||||
writer.WriteInt32(id.Value);
|
||||
writer.WriteInt32(attrib.ID);
|
||||
if (attrib.Command != default)
|
||||
writer.WriteInt32(attrib.Command);
|
||||
SpanWriter dataWriter = writer.Slice();
|
||||
packet.Save(ref dataWriter);
|
||||
writer.Position += dataWriter.Position;
|
||||
@ -107,18 +110,29 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
|
||||
|
||||
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
|
||||
|
||||
private IPacket GetPacket(int id)
|
||||
private IPacket GetPacket(ref SpanReader reader)
|
||||
{
|
||||
Type packetType = _cachedClasses.Where(x => x.attrib.ID == id).FirstOrDefault().type;
|
||||
return packetType == null
|
||||
? new RawPacket { ID = id }
|
||||
: (IPacket)Activator.CreateInstance(packetType);
|
||||
// Try to find a unique packet via ID only.
|
||||
int id = reader.ReadInt32();
|
||||
var packets = _cachedClasses.Where(x => x.attrib.ID == id).ToList();
|
||||
if (packets.Count == 1)
|
||||
return (IPacket)Activator.CreateInstance(packets[0].type);
|
||||
|
||||
// No unique packet found, check for matching command.
|
||||
int command = reader.ReadInt32();
|
||||
packets = packets.Where(x => x.attrib.Command == command).ToList();
|
||||
if (packets.Count == 1)
|
||||
return (IPacket)Activator.CreateInstance(packets[0].type);
|
||||
|
||||
// No unique packet found, return fallback.
|
||||
reader.Position -= sizeof(int);
|
||||
return new RawPacket { ID = id };
|
||||
}
|
||||
|
||||
private int? GetID(IPacket packet)
|
||||
private WwpaPacketAttribute GetAttribute(IPacket packet)
|
||||
{
|
||||
Type packetType = packet.GetType();
|
||||
return _cachedClasses.Where(x => x.type == packetType).FirstOrDefault().attrib?.ID;
|
||||
return _cachedClasses.Where(x => x.type == packetType).FirstOrDefault().attrib;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user