2019-01-15 22:48:56 +01:00

202 lines
7.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Syroot.Worms.Mgame.GameServer.Core;
using Syroot.Worms.Mgame.GameServer.Packets;
using Syroot.Worms.Mgame.GameServer.Packets.OnlineWorms;
namespace Syroot.Worms.Mgame.GameServer
{
/// <summary>
/// Represents a connection with an Online Worms client which replies to received packets appropriately.
/// </summary>
internal class Client : AppConnection
{
// ---- FIELDS -------------------------------------------------------------------------------------------------
private readonly Server _server;
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the <see cref="Client"/> class accepted by the given <paramref name="server"/>
/// through the provided <see cref="tcpClient"/>.
/// </summary>
/// <param name="tcpClient">The <see cref="TcpClient"/> representing the connection to the client.</param>
/// <param name="server">The <see cref="Server"/> instance with which this client communicates.</param>
internal Client(TcpClient tcpClient, Server server)
: base(tcpClient)
{
_server = server;
}
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
public void HandleConnect(ConnectQuery packet)
{
SendPacket(new ConnectReply
{
Unknown = _server.Config.Name,
Unknown2 = _server.Config.Region,
Version = _server.Config.Version
});
}
public void HandleLogin(LoginQuery packet)
{
// 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++)
{
LoginCredentials credentials = packet.Logins[i];
playerInfos[i] = new LoginPlayerInfo { ID = credentials.ID, Rank = 19 };
}
SendPacket(new LoginReply
{
Result = LoginResult.Success,
PlayerInfos = playerInfos
});
// Send info text.
SendPacket(new ServerInfoReply
{
Text = "Welcome to the Online Worms Server."
});
// Send channels. The port is abused to identify the channel later on.
SendPacket(new ChannelInfosReply
{
Channels = new[]
{
new ChannelInfo
{
Name = "Test Channel",
EndPoint = new IPEndPoint(_server.Config.IPAddress, 1),
Type = ChannelType.Normal,
Color = Color.LightGreen,
Load = ChannelLoad.Highest
},
new ChannelInfo
{
Name = "Real Channel",
EndPoint = new IPEndPoint(_server.Config.IPAddress, 2),
Type = ChannelType.Normal
},
new ChannelInfo
{
Name = "Boredom Time",
EndPoint = new IPEndPoint(_server.Config.IPAddress, 3),
Type = ChannelType.Normal,
Load = ChannelLoad.Medium
},
new ChannelInfo
{
Name = "Nothing Goes",
EndPoint = new IPEndPoint(_server.Config.IPAddress, 4),
Type = ChannelType.Roping,
Color = Color.Orange,
Coins = 2,
Load = ChannelLoad.Closed
},
new ChannelInfo
{
Name = "Doper's Heaven",
EndPoint = new IPEndPoint(_server.Config.IPAddress, 5),
Type = ChannelType.Roping,
Color = Color.Orange,
Coins = 1,
Load = ChannelLoad.Full
},
new ChannelInfo
{
Name = "Unhelpful Channel",
EndPoint = new IPEndPoint(_server.Config.IPAddress, 6),
Type = ChannelType.Special
}
}
});
}
public void HandleChannelEnter(ChannelEnterQuery packet)
{
// Simply allow joining a channel running on the same server port.
SendPacket(new ChannelEnterReply
{
EndPoint = _server.Config.EndPoint
});
}
public void HandleChannelConnect(ChannelConnectQuery packet)
{
SendPacket(new ChannelConnectReply
{
Result = ChannelConnectResult.Success,
Player = new ChannelConnectPlayerInfo
{
ID = packet.Players[0].ID,
Name = "Your Name",
Experience = 1337,
Gold = 1000000,
Rank = 19,
GuildMarkIndex = 1,
GuildName = "Your Guild"
}
});
}
public void HandleChannelTop20(ChannelTop20Query packet)
{
// Send some simulated player rank infos.
ChannelTop20Reply reply = new ChannelTop20Reply
{
UnknownA = "Test",
Top20 = new List<ChannelTop20Player>(20)
};
for (int i = 0; i < 20; i++)
{
reply.Top20.Add(new ChannelTop20Player
{
Name = $"GoodPlayer{(char)('A' + i)}",
Rank = (ushort)((i + 6) / 3),
Experience = (ulong)(20 - i) * 957
});
}
SendPacket(reply);
// This is the last channel info packet, tell the client to go to the channel screen.
SendPacket(new ChannelEnterFinishReply());
}
public void HandleStartSingleGameQuery(StartSingleGameQuery packet)
{
SendPacket(new StartSingleGameReply
{
Success = packet.RoundType == GameStartRoundType.First
});
}
#if DEBUG
public void HandleRaw(RawPacket packet) { }
#endif
// ---- METHODS (PROTECTED) ------------------------------------------------------------------------------------
protected override void OnPrePacketHandle(Packet packet)
{
_server.Log.Write(LogCategory.Client,
$"{TcpClient.Client.RemoteEndPoint} >> {packet}{Environment.NewLine}{ObjectDumper.Dump(packet)}");
}
protected override void OnPrePacketSend(Packet packet)
{
_server.Log.Write(LogCategory.Server,
$"{TcpClient.Client.RemoteEndPoint} << {packet}{Environment.NewLine}{ObjectDumper.Dump(packet)}");
if (_server.Config.SendDelay > 0)
Thread.Sleep(_server.Config.SendDelay);
}
}
}