mirror of
https://gitlab.com/Syroot/Worms.git
synced 2025-04-12 04:10:06 +03:00
101 lines
4.0 KiB
C#
101 lines
4.0 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Net.Sockets;
|
|
using System.Reflection;
|
|
|
|
namespace Syroot.Worms.OnlineWorms.Server.Net
|
|
{
|
|
/// <summary>
|
|
/// Represents a class capable of dispatching received <see cref="Packet"/> instances to a corresponding method.
|
|
/// </summary>
|
|
internal class PacketHandler : IDisposable
|
|
{
|
|
// ---- FIELDS -------------------------------------------------------------------------------------------------
|
|
|
|
private static readonly Dictionary<Type, Dictionary<Type, MethodInfo>> _packetHandlers
|
|
= new Dictionary<Type, Dictionary<Type, MethodInfo>>();
|
|
|
|
private readonly TcpClient _tcpClient;
|
|
private readonly Dictionary<Type, MethodInfo> _handlerMethods;
|
|
private readonly GameConnection _connection;
|
|
private bool _disposed;
|
|
|
|
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
|
|
|
internal PacketHandler(TcpClient tcpClient)
|
|
{
|
|
Console.WriteLine($"{tcpClient.Client.RemoteEndPoint} connected");
|
|
_tcpClient = tcpClient;
|
|
_handlerMethods = GetHandlerMethods();
|
|
_connection = new GameConnection(_tcpClient);
|
|
}
|
|
|
|
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
|
|
|
public void Dispose()
|
|
{
|
|
// Do not change this code. Put cleanup code in Dispose(bool disposing).
|
|
Dispose(true);
|
|
}
|
|
|
|
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
|
|
|
|
/// <summary>
|
|
/// Starts handling packets incoming from this client and calls corresponding methods.
|
|
/// </summary>
|
|
internal void Accept()
|
|
{
|
|
Packet packet;
|
|
while ((packet = _connection.ReceivePacket()) != null)
|
|
HandlePacket(packet);
|
|
}
|
|
|
|
// ---- METHODS (PROTECTED) ------------------------------------------------------------------------------------
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (!_disposed)
|
|
{
|
|
if (disposing)
|
|
_tcpClient.Dispose();
|
|
|
|
_disposed = true;
|
|
}
|
|
}
|
|
|
|
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
|
|
|
|
private Dictionary<Type, MethodInfo> GetHandlerMethods()
|
|
{
|
|
Type classType = GetType();
|
|
if (!_packetHandlers.TryGetValue(classType, out Dictionary<Type, MethodInfo> handlerMethods))
|
|
{
|
|
handlerMethods = new Dictionary<Type, MethodInfo>();
|
|
// Find all packet handling methods which are methods accepting and returning a specific packet.
|
|
foreach (MethodInfo method in classType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance))
|
|
{
|
|
Type inPacket = method.GetParameters().FirstOrDefault()?.ParameterType;
|
|
if (typeof(Packet).IsAssignableFrom(inPacket) && typeof(Packet).IsAssignableFrom(method.ReturnType))
|
|
handlerMethods.Add(inPacket, method);
|
|
}
|
|
_packetHandlers.Add(classType, handlerMethods);
|
|
}
|
|
return handlerMethods;
|
|
}
|
|
|
|
private void HandlePacket(Packet inPacket)
|
|
{
|
|
Type packetType = inPacket.GetType();
|
|
Console.WriteLine($"{_tcpClient.Client.RemoteEndPoint} >> {packetType.Name}");
|
|
|
|
// Invoke the handler and send back any packet resulting from it.
|
|
if (_handlerMethods[packetType].Invoke(this, new[] { inPacket }) is Packet outPacket)
|
|
{
|
|
Console.WriteLine($"{_tcpClient.Client.RemoteEndPoint} << {outPacket.GetType().Name}");
|
|
_connection.SendPacket(outPacket);
|
|
}
|
|
}
|
|
}
|
|
}
|