Implement ChannelList and ChannelLoginQuery

This commit is contained in:
Ray Koopa 2019-01-19 15:38:48 +01:00
parent 587ac06330
commit b527021df4
14 changed files with 253 additions and 77 deletions

View File

@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Drawing;
using System.Net;
using Syroot.Worms.Mgame.GameServer.Packets.Data;
using Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms;
namespace Syroot.Worms.Mgame.GameServer
@ -23,11 +24,11 @@ namespace Syroot.Worms.Mgame.GameServer
{
// Send login result.
// Create player infos from the given credentials. This would be the place to check for actual accounts.
LoginPlayerInfo[] playerInfos = new LoginPlayerInfo[packet.Logins.Length];
for (int i = 0; i < packet.Logins.Length; i++)
LoginPlayerInfo[] playerInfos = new LoginPlayerInfo[packet.Players.Length];
for (int i = 0; i < packet.Players.Length; i++)
{
LoginCredentials credentials = packet.Logins[i];
playerInfos[i] = new LoginPlayerInfo { ID = credentials.ID, Rank = 19 };
PlayerCredentials credentials = packet.Players[i];
playerInfos[i] = new LoginPlayerInfo { ID = credentials.UserName, Rank = 19 };
}
SendPacket(new LoginReply
{
@ -104,14 +105,14 @@ namespace Syroot.Worms.Mgame.GameServer
});
}
public void HandleOWChannelConnect(ChannelConnectQuery packet)
public void HandleOWChannelConnect(ChannelLoginQuery packet)
{
SendPacket(new ChannelConnectReply
SendPacket(new ChannelLoginReply
{
Result = ChannelConnectResult.Success,
Player = new ChannelConnectPlayerInfo
{
ID = packet.Players[0].ID,
ID = packet.Players[0].UserName,
Name = "Your Name",
Experience = 1337,
Gold = 1000000,

View File

@ -9,6 +9,7 @@ namespace Syroot.Worms.Mgame.GameServer
public void HandleWwpaConnect(ConnectQuery packet)
{
// Client fails to detect reply at rare times due to unknown reasons.
SendPacket(new ConnectReply { ServerVersion = _server.Config.Version });
}
@ -17,9 +18,82 @@ namespace Syroot.Worms.Mgame.GameServer
SendPacket(new LoginReply { Result = LoginResult.Success });
}
public void HandleWwpaLoginAcknowledge(ChannelListQuery packet)
public void HandleWwpaChannelList(ChannelListQuery packet)
{
SendPacket(new ChannelListReply { Channels = new List<ChannelInfo>() });
SendPacket(new ChannelListReply
{
Channels = new List<ChannelInfo>
{
new ChannelInfo
{
UnknownA = 0x11,
UnknownD = 0x22,
Name = "Party Hard",
EndPoint = _server.Config.EndPoint,
Type = ChannelType.Normal,
Status = ChannelStatus.Load2
},
new ChannelInfo
{
UnknownA = 0x33,
UnknownD = 0x44,
Name = "Pay 2 Win",
EndPoint = _server.Config.EndPoint,
Type = ChannelType.Normal,
Status = ChannelStatus.Closed
},
new ChannelInfo
{
UnknownA = 0x55,
UnknownD = 0x66,
Name = "Free 4 None",
EndPoint = _server.Config.EndPoint,
Type = ChannelType.Normal,
Status = ChannelStatus.Load1
},
new ChannelInfo
{
UnknownA = 0x77,
UnknownD = 0x88,
Name = "Nothing Goes",
EndPoint = _server.Config.EndPoint,
Type = ChannelType.Roping,
Status = ChannelStatus.Full
},
new ChannelInfo
{
UnknownA = 0x99,
UnknownD = 0xAA,
Name = "Ropers Hell",
EndPoint = _server.Config.EndPoint,
Type = ChannelType.Roping,
Status = ChannelStatus.Load3
},
new ChannelInfo
{
UnknownA = 0xBB,
UnknownD = 0xCC,
Name = "Gay Guilds",
EndPoint = _server.Config.EndPoint,
Type = ChannelType.Guild,
Status = ChannelStatus.Load2
},
new ChannelInfo
{
UnknownA = 0xDD,
UnknownD = 0xEE,
Name = "Enormous Event",
EndPoint = _server.Config.EndPoint,
Type = ChannelType.Event,
Status = ChannelStatus.Closed
}
}
});
}
public void HandleWwpaChannelConnect(ChannelLoginQuery packet)
{
}
public void HandleWwpaDisconnectQuery(DisconnectQuery packet) { }

View File

@ -1,4 +1,5 @@
using System.Drawing;
using System.Net;
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Core.IO
@ -11,10 +12,10 @@ namespace Syroot.Worms.Mgame.GameServer.Core.IO
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
/// <summary>
/// Writes the given <paramref name="color"/> as an RGB0 integer value.
/// Writes the given <see cref="Color"/> as an RGB0 integer value.
/// </summary>
/// <param name="self">The extended instance.</param>
/// <param name="color">The <see cref="Color"/> to write.</param>
/// <param name="value">The value to write.</param>
internal static void WriteColor(this ref SpanWriter self, Color color)
{
self.WriteByte(color.R);
@ -22,5 +23,16 @@ namespace Syroot.Worms.Mgame.GameServer.Core.IO
self.WriteByte(color.B);
self.WriteByte(0);
}
/// <summary>
/// Writes the given <see cref="IPEndPoint"/> as 4 separate address bytes and a 2-byte port.
/// </summary>
/// <param name="self">The extended instance.</param>
/// <param name="value">The value to write.</param>
internal static void WriteIPEndPoint(this ref SpanWriter self, IPEndPoint value)
{
self.WriteBytes(value.Address.GetAddressBytes());
self.WriteUInt16((ushort)value.Port);
}
}
}

View File

@ -1,4 +1,5 @@
using System;
using System.Diagnostics;
namespace Syroot.Worms.Mgame.GameServer
{
@ -19,6 +20,7 @@ namespace Syroot.Worms.Mgame.GameServer
private void Write(ConsoleColor color, string text)
{
Debug.WriteLine(text);
lock (_lock)
{
ConsoleColor prevColor = Console.ForegroundColor;

View File

@ -238,7 +238,9 @@ namespace Syroot.Worms.Mgame.GameServer.Packets
// Retrieve (decompressed) data.
SpanWriter writer = new SpanWriter(new byte[_maxDataSize], encoding: Encodings.Korean);
writer.WriteInt32(id);
packet.Save(ref writer);
SpanWriter dataWriter = writer.Slice();
packet.Save(ref dataWriter);
writer.Position += dataWriter.Position;
// Send head and data.
_tcpStream.WriteUInt16(_wwpaTagStart);

View File

@ -0,0 +1,32 @@
using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.Data
{
/// <summary>
/// Represents the authentication credentials for a player account sent with LoginQuery and ChanneLoginQuery
/// packets.
/// </summary>
internal class PlayerCredentials
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
/// <summary>
/// Gets or sets the name of the player to login.
/// </summary>
internal string UserName { get; set; }
/// <summary>
/// Gets or sets the password with which the player profile is authenticated.
/// </summary>
internal string Password { get; set; }
}
internal static partial class SpanReaderExtensions
{
internal static PlayerCredentials ReadCredentials(this ref SpanReader self) => new PlayerCredentials
{
UserName = self.ReadString2(),
Password = self.ReadString2()
};
}
}

View File

@ -20,8 +20,8 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
internal override void Load(ref SpanReader reader)
{
PlayerID = reader.ReadString();
ChannelEndPoint = new IPEndPoint(IPAddress.Parse(reader.ReadString()), reader.ReadUInt16());
PlayerID = reader.ReadString2();
ChannelEndPoint = new IPEndPoint(IPAddress.Parse(reader.ReadString2()), reader.ReadUInt16());
}
internal override void Save(ref SpanWriter writer) => throw new NotImplementedException();

View File

@ -2,18 +2,19 @@
using System.Collections.Generic;
using System.Net;
using Syroot.BinaryData.Memory;
using Syroot.Worms.Mgame.GameServer.Packets.Data;
namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
{
/// <summary>
/// Represents the client request for a <see cref="ChannelConnectReply"/>.
/// Represents the client request for a <see cref="ChannelLoginReply"/>.
/// </summary>
[Packet(PacketFormat.OWChannel, 0x10)]
internal class ChannelConnectQuery : Packet
internal class ChannelLoginQuery : Packet
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
public IList<ChannelConnectPlayerCredentials> Players { get; set; }
public IList<PlayerCredentials> Players { get; set; }
public IPAddress ClientIP { get; set; }
@ -27,11 +28,11 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
internal override void Load(ref SpanReader reader)
{
Players = new List<ChannelConnectPlayerCredentials>
Players = new List<PlayerCredentials>
{
new ChannelConnectPlayerCredentials
new PlayerCredentials
{
ID = reader.ReadStringFix(12),
UserName = reader.ReadStringFix(12),
Password = reader.ReadStringFix(12)
}
};
@ -42,9 +43,9 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
ushort additionalPlayers = reader.ReadUInt16();
for (int i = 0; i < additionalPlayers; i++)
{
Players.Add(new ChannelConnectPlayerCredentials
Players.Add(new PlayerCredentials
{
ID = reader.ReadStringFix(12),
UserName = reader.ReadStringFix(12),
Password = reader.ReadStringFix(12)
});
}
@ -53,10 +54,4 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
internal override void Save(ref SpanWriter writer) => throw new NotImplementedException();
}
internal class ChannelConnectPlayerCredentials
{
public string ID { get; set; } // Max. 12 characters.
public string Password { get; set; } // Max. 12 characters.
}
}

View File

@ -4,10 +4,10 @@ using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
{
/// <summary>
/// Represents the server response to a <see cref="ChannelConnectQuery"/>.
/// Represents the server response to a <see cref="ChannelLoginQuery"/>.
/// </summary>
[Packet(PacketFormat.OWChannel, 0x11)]
internal class ChannelConnectReply : Packet
internal class ChannelLoginReply : Packet
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------

View File

@ -4,7 +4,7 @@ using Syroot.BinaryData.Memory;
namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
{
/// <summary>
/// Represents the client request for a <see cref="ChannelConnectReply"/>.
/// Represents the client request for a <see cref="ChannelLoginReply"/>.
/// </summary>
[Packet(PacketFormat.OWChannel, 0x37)]
internal class ChannelTop20Query : Packet

View File

@ -1,6 +1,7 @@
using System;
using System.Net;
using Syroot.BinaryData.Memory;
using Syroot.Worms.Mgame.GameServer.Packets.Data;
namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
{
@ -14,7 +15,7 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
internal ushort Unknown1 { get; set; }
internal LoginCredentials[] Logins { get; set; }
internal PlayerCredentials[] Players { get; set; }
internal IPAddress ClientIP { get; set; }
@ -23,24 +24,12 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms
internal override void Load(ref SpanReader reader)
{
Unknown1 = reader.ReadUInt16();
Logins = new LoginCredentials[reader.ReadUInt16()];
for (int i = 0; i < Logins.Length; i++)
{
Logins[i] = new LoginCredentials
{
ID = reader.ReadString(),
Password = reader.ReadString()
};
}
ClientIP = IPAddress.Parse(reader.ReadString());
Players = new PlayerCredentials[reader.ReadUInt16()];
for (int i = 0; i < Players.Length; i++)
Players[i] = reader.ReadCredentials();
ClientIP = IPAddress.Parse(reader.ReadString2());
}
internal override void Save(ref SpanWriter writer) => throw new NotImplementedException();
}
internal class LoginCredentials
{
internal string ID { get; set; }
internal string Password { get; set; }
}
}

View File

@ -1,6 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using Syroot.BinaryData.Memory;
using Syroot.Worms.Mgame.GameServer.Core.IO;
namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
{
@ -14,8 +17,6 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
public IList<ChannelInfo> Channels { get; set; }
public byte Unknown { get; set; }
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader) => throw new NotImplementedException();
@ -23,16 +24,65 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
internal override void Save(ref SpanWriter writer)
{
writer.WriteUInt16((ushort)Channels.Count);
writer.WriteByte(Unknown);
writer.Align(4);
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));
foreach (ChannelInfo channel in Channels)
{
writer.WriteUInt16(channel.UnknownA);
writer.WriteString2(channel.Name);
writer.WriteIPEndPoint(channel.EndPoint);
writer.WriteEnum(channel.Type);
writer.WriteByte(channel.UnknownD);
writer.WriteEnum(channel.Status);
}
}
}
internal class ChannelInfo
{
internal ushort UnknownA { get; set; }
/// <summary>
/// Gets or sets the name of the channel. Should not exceed 32 characters.
/// </summary>
internal string Name { get; set; }
/// <summary>
/// Gets or sets the IP address to connect to.
/// </summary>
internal IPEndPoint EndPoint { get; set; }
/// <summary>
/// Gets or sets the category in which the channel will appear.
/// </summary>
internal ChannelType Type { get; set; }
internal byte UnknownD { get; set; }
/// <summary>
/// Gets or sets the channel load or status.
/// </summary>
internal ChannelStatus Status { get; set; }
}
internal enum ChannelType : byte
{
Normal = 0,
Roping = 1,
Guild = 2,
Event = 3
}
internal enum ChannelStatus : byte
{
Closed = 0,
Load1 = 1,
Load2 = 2,
Load3 = 3,
Load4 = 4,
Load5 = 5,
Full = 6
}
}

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Net;
using Syroot.BinaryData.Memory;
using Syroot.Worms.Mgame.GameServer.Core.IO;
using Syroot.Worms.Mgame.GameServer.Packets.Data;
namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
{
/// <summary>
/// Represents the client request for a <see cref="ChannelConnectReply"/>.
/// </summary>
[Packet(PacketFormat.Wwpa, 0x101)]
internal class ChannelLoginQuery : Packet
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
public IPAddress IPAddress { get; set; }
public IList<PlayerCredentials> Players { get; set; }
public byte UnknownA { get; set; }
public byte UnknownB { get; set; }
public byte[] Remain { get; set; }
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader)
{
IPAddress = IPAddress.Parse(reader.ReadString2());
Players = new List<PlayerCredentials> { reader.ReadCredentials() };
if (reader.ReadBoolean())
Players.Add(reader.ReadCredentials());
UnknownA = reader.ReadByte();
UnknownB = reader.ReadByte();
Remain = reader.ReadToEnd();
}
internal override void Save(ref SpanWriter writer) => throw new NotImplementedException();
}
}

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Syroot.BinaryData.Memory;
using Syroot.Worms.Mgame.GameServer.Packets.Data;
namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
{
@ -15,38 +16,17 @@ namespace Syroot.Worms.Mgame.GameServer.Packets.WorldPartyAqua
/// <summary>
/// Gets or sets the names and passwords of the players to login.
/// </summary>
public IList<LoginCredentials> Logins { get; set; }
public IList<PlayerCredentials> Players { get; set; }
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
internal override void Load(ref SpanReader reader)
{
Logins = new List<LoginCredentials> { ReadCredentials(ref reader) };
Players = new List<PlayerCredentials> { reader.ReadCredentials() };
if (reader.ReadBoolean())
Logins.Add(ReadCredentials(ref reader));
Players.Add(reader.ReadCredentials());
}
internal override void Save(ref SpanWriter writer) => throw new NotImplementedException();
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
private static LoginCredentials ReadCredentials(ref SpanReader reader) => new LoginCredentials
{
UserName = reader.ReadString2(),
Password = reader.ReadString2()
};
}
internal class LoginCredentials
{
/// <summary>
/// Gets or sets the name of the player to login.
/// </summary>
internal string UserName { get; set; }
/// <summary>
/// Gets or sets the password with which the player profile is authenticated.
/// </summary>
internal string Password { get; set; }
}
}