|
|
@@ -5,11 +5,6 @@ using System.Net.Sockets;
|
|
|
using System.Text;
|
|
|
using System.Threading.Tasks;
|
|
|
using System.Threading.Tasks.Dataflow;
|
|
|
-using MineCase.Gateway.Network.Handler;
|
|
|
-using MineCase.Gateway.Network.Handler.Handshaking;
|
|
|
-using MineCase.Gateway.Network.Handler.Login;
|
|
|
-using MineCase.Gateway.Network.Handler.Play;
|
|
|
-using MineCase.Gateway.Network.Handler.Status;
|
|
|
using MineCase.Protocol.Protocol;
|
|
|
using MineCase.Protocol.Protocol.Handshaking.Server;
|
|
|
using MineCase.Protocol.Protocol.Login.Server;
|
|
|
@@ -22,42 +17,24 @@ namespace MineCase.Gateway.Network
|
|
|
{
|
|
|
public class ClientSession : IDisposable
|
|
|
{
|
|
|
- private readonly Guid _sessionId;
|
|
|
+ private readonly Guid _sessionId = Guid.NewGuid();
|
|
|
private TcpClient _tcpClient = null;
|
|
|
private IClusterClient _client = null;
|
|
|
private NetworkStream _dataStream = null;
|
|
|
|
|
|
- private volatile bool _useCompression = false;
|
|
|
- private uint _compressThreshold;
|
|
|
-
|
|
|
private bool disposed = false;
|
|
|
|
|
|
- private PacketInfo _packetInfo;
|
|
|
- private PacketEncoder _encoder;
|
|
|
- private PacketDecoder _decoder;
|
|
|
- private INetHandler _packetHandler;
|
|
|
-
|
|
|
- private SessionState _sessionState = SessionState.Handshake;
|
|
|
-
|
|
|
- private readonly ActionBlock<ISerializablePacket> _outcomingPacketDispatcher;
|
|
|
+ private readonly ActionBlock<RawPacket> _outcomingPacketDispatcher = null;
|
|
|
|
|
|
- private IClientboundPacketObserver _clientboundPacketObserverRef;
|
|
|
+ private IClientboundPacketObserver _clientboundPacketObserverRef = null;
|
|
|
|
|
|
private readonly OutcomingPacketObserver _outcomingPacketObserver;
|
|
|
|
|
|
public ClientSession(TcpClient tcpClient, IClusterClient clusterClient)
|
|
|
{
|
|
|
- _sessionId = Guid.NewGuid();
|
|
|
_tcpClient = tcpClient;
|
|
|
_client = clusterClient;
|
|
|
-
|
|
|
- _packetInfo = new PacketInfo();
|
|
|
- _encoder = new PacketEncoder(PacketDirection.ClientBound, _packetInfo);
|
|
|
- _decoder = new PacketDecoder(PacketDirection.ServerBound, _packetInfo);
|
|
|
- _packetHandler = new ServerHandshakeNetHandler(this, _client);
|
|
|
- _outcomingPacketDispatcher = new ActionBlock<ISerializablePacket>(SendOutcomingPacket);
|
|
|
-
|
|
|
- _clientboundPacketObserverRef = null;
|
|
|
+ _outcomingPacketDispatcher = new ActionBlock<RawPacket>(SendOutcomingPacket);
|
|
|
_outcomingPacketObserver = new OutcomingPacketObserver(this);
|
|
|
}
|
|
|
|
|
|
@@ -100,30 +77,6 @@ namespace MineCase.Gateway.Network
|
|
|
{
|
|
|
}
|
|
|
|
|
|
- // Switch session state
|
|
|
- public void SetSessionState(SessionState state)
|
|
|
- {
|
|
|
- _sessionState = state;
|
|
|
- }
|
|
|
-
|
|
|
- public void SetNetHandler(SessionState state)
|
|
|
- {
|
|
|
- switch (state)
|
|
|
- {
|
|
|
- case SessionState.Login:
|
|
|
- _packetHandler = new ServerLoginNetHandler(this, _client);
|
|
|
- break;
|
|
|
- case SessionState.Status:
|
|
|
- _packetHandler = new ServerStatusNetHandler(this, _client);
|
|
|
- break;
|
|
|
- case SessionState.Play:
|
|
|
- _packetHandler = new ServerPlayNetHandler(this, _client);
|
|
|
- break;
|
|
|
- default:
|
|
|
- throw new NotImplementedException("Invalid intention " + state.ToString());
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
// Startup session
|
|
|
public async Task Startup()
|
|
|
{
|
|
|
@@ -155,21 +108,19 @@ namespace MineCase.Gateway.Network
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Send Packet to game clients
|
|
|
- public async Task SendPacket(ISerializablePacket packet)
|
|
|
+ // Process raw packet
|
|
|
+ private async Task ProcessPacket()
|
|
|
{
|
|
|
- try
|
|
|
- {
|
|
|
- if (!_outcomingPacketDispatcher.Completion.IsCompleted)
|
|
|
- await _outcomingPacketDispatcher.SendAsync(packet);
|
|
|
- }
|
|
|
- catch
|
|
|
- {
|
|
|
- _outcomingPacketDispatcher.Complete();
|
|
|
- }
|
|
|
+ // Read raw packet
|
|
|
+ RawPacket rawPacket = new RawPacket();
|
|
|
+ await rawPacket.DeserializeAsync(_dataStream);
|
|
|
+
|
|
|
+ var router = _client.GetGrain<IPacketRouter>(_sessionId);
|
|
|
+ await router.ProcessPacket(rawPacket);
|
|
|
}
|
|
|
|
|
|
- public async void DispatchOutcomingPacket(ISerializablePacket packet)
|
|
|
+ // Send Packet to game clients
|
|
|
+ public async void DispatchOutcomingPacket(RawPacket packet)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
@@ -182,7 +133,7 @@ namespace MineCase.Gateway.Network
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private async Task SendOutcomingPacket(ISerializablePacket packet)
|
|
|
+ private async Task SendOutcomingPacket(RawPacket packet)
|
|
|
{
|
|
|
if (packet == null)
|
|
|
{
|
|
|
@@ -191,127 +142,11 @@ namespace MineCase.Gateway.Network
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- RawPacket rawPacket = new RawPacket();
|
|
|
- using (MemoryStream ms = new MemoryStream())
|
|
|
- {
|
|
|
- if (_useCompression)
|
|
|
- _encoder.Encode(packet, ms);
|
|
|
- else
|
|
|
- _encoder.Encode(packet, ms);
|
|
|
- rawPacket.RawData = ms.ToArray();
|
|
|
- rawPacket.Length = rawPacket.RawData.Length;
|
|
|
- }
|
|
|
-
|
|
|
// System.Console.WriteLine($"Send packet id:{_packetInfo.GetPacketId(packet):x2}, length: {rawPacket.Length}");
|
|
|
- await rawPacket.SerializeAsync(_dataStream);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Process packets from game clients
|
|
|
- private async Task ProcessPacket()
|
|
|
- {
|
|
|
- // Read raw packet
|
|
|
- RawPacket rawPacket = new RawPacket();
|
|
|
- await rawPacket.DeserializeAsync(_dataStream);
|
|
|
-
|
|
|
- // Read packet
|
|
|
- ISerializablePacket packet = null;
|
|
|
- using (MemoryStream ms = new MemoryStream(rawPacket.RawData))
|
|
|
- {
|
|
|
- packet = _decoder.Decode((ProtocolType)_sessionState, ms);
|
|
|
- }
|
|
|
-
|
|
|
- switch (_sessionState)
|
|
|
- {
|
|
|
- case SessionState.Handshake:
|
|
|
- await ProcessHandshakePacket(packet);
|
|
|
- break;
|
|
|
- case SessionState.Login:
|
|
|
- await ProcessLoginPacket(packet);
|
|
|
- break;
|
|
|
- case SessionState.Play:
|
|
|
- await ProcessPlayPacket(packet);
|
|
|
- break;
|
|
|
- case SessionState.Status:
|
|
|
- await ProcessStatusPacket(packet);
|
|
|
- break;
|
|
|
- default:
|
|
|
- throw new InvalidDataException($"Invalid session state.");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private async Task ProcessStatusPacket(ISerializablePacket packet)
|
|
|
- {
|
|
|
- var handler = (IServerStatusNetHandler)_packetHandler;
|
|
|
- int packetId = _packetInfo.GetPacketId(packet);
|
|
|
- switch (packetId)
|
|
|
- {
|
|
|
- // request
|
|
|
- case 0x00:
|
|
|
- await handler.ProcessRequest((Request)packet);
|
|
|
- break;
|
|
|
-
|
|
|
- // ping
|
|
|
- case 0x01:
|
|
|
- await handler.ProcessPing((Ping)packet);
|
|
|
- break;
|
|
|
- default:
|
|
|
- throw new InvalidDataException($"Unrecognizable packet id: 0x{packetId:X2}.");
|
|
|
+ await packet.SerializeAsync(_dataStream);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private async Task ProcessHandshakePacket(ISerializablePacket packet)
|
|
|
- {
|
|
|
- var handler = (IHandshakeNetHandler)_packetHandler;
|
|
|
- int packetId = _packetInfo.GetPacketId(packet);
|
|
|
- switch (packetId)
|
|
|
- {
|
|
|
- // handshake
|
|
|
- case 0x00:
|
|
|
- await handler.ProcessHandshake((Handshake)packet);
|
|
|
- break;
|
|
|
- default:
|
|
|
- throw new InvalidDataException($"Unrecognizable packet id: 0x{packetId:X2}.");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private async Task ProcessLoginPacket(ISerializablePacket packet)
|
|
|
- {
|
|
|
- var handler = (IServerLoginNetHandler)_packetHandler;
|
|
|
- int packetId = _packetInfo.GetPacketId(packet);
|
|
|
- switch (packetId)
|
|
|
- {
|
|
|
- // Login Start
|
|
|
- case 0x00:
|
|
|
- await handler.ProcessLoginStart((LoginStart)packet);
|
|
|
- break;
|
|
|
-
|
|
|
- // Encryption Response
|
|
|
- case 0x01:
|
|
|
- await handler.ProcessEncryptionResponse((EncryptionResponse)packet);
|
|
|
- break;
|
|
|
- default:
|
|
|
- throw new InvalidDataException($"Unrecognizable packet id: 0x{packetId:X2}.");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private Task ProcessPlayPacket(ISerializablePacket packet)
|
|
|
- {
|
|
|
- var handler = (IServerPlayNetHandler)_packetHandler;
|
|
|
- int packetId = _packetInfo.GetPacketId(packet);
|
|
|
- switch (packetId)
|
|
|
- {
|
|
|
- // handshake
|
|
|
- case 0x00:
|
|
|
- // await handler.ProcessHandshake((Handshake)packet);
|
|
|
- break;
|
|
|
- default:
|
|
|
- throw new InvalidDataException($"Unrecognizable packet id: 0x{packetId:X2}.");
|
|
|
- }
|
|
|
-
|
|
|
- return Task.CompletedTask;
|
|
|
- }
|
|
|
-
|
|
|
private class OutcomingPacketObserver : IClientboundPacketObserver
|
|
|
{
|
|
|
private readonly ClientSession _session;
|
|
|
@@ -326,7 +161,7 @@ namespace MineCase.Gateway.Network
|
|
|
_session.OnClosed();
|
|
|
}
|
|
|
|
|
|
- public void ReceivePacket(ISerializablePacket packet)
|
|
|
+ public void ReceivePacket(RawPacket packet)
|
|
|
{
|
|
|
_session.DispatchOutcomingPacket(packet);
|
|
|
}
|