From 0aff93c33ea017765bfb7fd53c87f126cc824b44 Mon Sep 17 00:00:00 2001 From: qwqtoday Date: Sat, 1 Jun 2024 14:55:55 +0800 Subject: [PATCH 1/8] move all client packet handlers to Packets\Handlers\Client --- .../Packets/Handlers/{ => Client}/ConfigurationPacketHandler.cs | 0 .../Packets/Handlers/{ => Client}/HandshakePacketHandler.cs | 0 .../Packets/Handlers/{ => Client}/LoginPacketHandler.cs | 0 .../Packets/Handlers/{ => Client}/PlayPacketHandler.cs | 0 .../Packets/Handlers/{ => Client}/StatusPacketHandler.cs | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename Components/MineSharp.Protocol/Packets/Handlers/{ => Client}/ConfigurationPacketHandler.cs (100%) rename Components/MineSharp.Protocol/Packets/Handlers/{ => Client}/HandshakePacketHandler.cs (100%) rename Components/MineSharp.Protocol/Packets/Handlers/{ => Client}/LoginPacketHandler.cs (100%) rename Components/MineSharp.Protocol/Packets/Handlers/{ => Client}/PlayPacketHandler.cs (100%) rename Components/MineSharp.Protocol/Packets/Handlers/{ => Client}/StatusPacketHandler.cs (100%) diff --git a/Components/MineSharp.Protocol/Packets/Handlers/ConfigurationPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/Client/ConfigurationPacketHandler.cs similarity index 100% rename from Components/MineSharp.Protocol/Packets/Handlers/ConfigurationPacketHandler.cs rename to Components/MineSharp.Protocol/Packets/Handlers/Client/ConfigurationPacketHandler.cs diff --git a/Components/MineSharp.Protocol/Packets/Handlers/HandshakePacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/Client/HandshakePacketHandler.cs similarity index 100% rename from Components/MineSharp.Protocol/Packets/Handlers/HandshakePacketHandler.cs rename to Components/MineSharp.Protocol/Packets/Handlers/Client/HandshakePacketHandler.cs diff --git a/Components/MineSharp.Protocol/Packets/Handlers/LoginPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/Client/LoginPacketHandler.cs similarity index 100% rename from Components/MineSharp.Protocol/Packets/Handlers/LoginPacketHandler.cs rename to Components/MineSharp.Protocol/Packets/Handlers/Client/LoginPacketHandler.cs diff --git a/Components/MineSharp.Protocol/Packets/Handlers/PlayPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/Client/PlayPacketHandler.cs similarity index 100% rename from Components/MineSharp.Protocol/Packets/Handlers/PlayPacketHandler.cs rename to Components/MineSharp.Protocol/Packets/Handlers/Client/PlayPacketHandler.cs diff --git a/Components/MineSharp.Protocol/Packets/Handlers/StatusPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/Client/StatusPacketHandler.cs similarity index 100% rename from Components/MineSharp.Protocol/Packets/Handlers/StatusPacketHandler.cs rename to Components/MineSharp.Protocol/Packets/Handlers/Client/StatusPacketHandler.cs From 6f540cbfd086d2876bca5acd8185816663a9498a Mon Sep 17 00:00:00 2001 From: qwqtoday Date: Sat, 1 Jun 2024 14:56:45 +0800 Subject: [PATCH 2/8] update Client handler namespace --- .../Packets/Handlers/Client/ConfigurationPacketHandler.cs | 4 ++-- .../Packets/Handlers/Client/HandshakePacketHandler.cs | 4 ++-- .../Packets/Handlers/Client/LoginPacketHandler.cs | 4 ++-- .../Packets/Handlers/Client/PlayPacketHandler.cs | 2 +- .../Packets/Handlers/Client/StatusPacketHandler.cs | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Components/MineSharp.Protocol/Packets/Handlers/Client/ConfigurationPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/Client/ConfigurationPacketHandler.cs index c609bcd8..1bf99702 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/Client/ConfigurationPacketHandler.cs +++ b/Components/MineSharp.Protocol/Packets/Handlers/Client/ConfigurationPacketHandler.cs @@ -1,10 +1,10 @@ -using MineSharp.Core.Common.Protocol; +using MineSharp.Core.Common.Protocol; using MineSharp.Data; using MineSharp.Data.Protocol; using MineSharp.Protocol.Packets.Clientbound.Configuration; using NLog; -namespace MineSharp.Protocol.Packets.Handlers; +namespace MineSharp.Protocol.Packets.Handlers.Client; internal class ConfigurationPacketHandler : IPacketHandler { diff --git a/Components/MineSharp.Protocol/Packets/Handlers/Client/HandshakePacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/Client/HandshakePacketHandler.cs index fbb1c15a..e3354f0a 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/Client/HandshakePacketHandler.cs +++ b/Components/MineSharp.Protocol/Packets/Handlers/Client/HandshakePacketHandler.cs @@ -1,8 +1,8 @@ -using MineSharp.Data.Protocol; +using MineSharp.Data.Protocol; using MineSharp.Protocol.Exceptions; using MineSharp.Protocol.Packets.Serverbound.Handshaking; -namespace MineSharp.Protocol.Packets.Handlers; +namespace MineSharp.Protocol.Packets.Handlers.Client; internal class HandshakePacketHandler : IPacketHandler { diff --git a/Components/MineSharp.Protocol/Packets/Handlers/Client/LoginPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/Client/LoginPacketHandler.cs index bad5bb89..807eaad8 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/Client/LoginPacketHandler.cs +++ b/Components/MineSharp.Protocol/Packets/Handlers/Client/LoginPacketHandler.cs @@ -1,4 +1,4 @@ -using MineSharp.Auth.Exceptions; +using MineSharp.Auth.Exceptions; using MineSharp.Core.Common; using MineSharp.Core.Common.Protocol; using MineSharp.Data; @@ -10,7 +10,7 @@ using System.Diagnostics; using System.Security.Cryptography; -namespace MineSharp.Protocol.Packets.Handlers; +namespace MineSharp.Protocol.Packets.Handlers.Client; internal class LoginPacketHandler : IPacketHandler { diff --git a/Components/MineSharp.Protocol/Packets/Handlers/Client/PlayPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/Client/PlayPacketHandler.cs index dc848be1..01428059 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/Client/PlayPacketHandler.cs +++ b/Components/MineSharp.Protocol/Packets/Handlers/Client/PlayPacketHandler.cs @@ -4,7 +4,7 @@ using MineSharp.Protocol.Packets.Serverbound.Play; using KeepAlivePacket = MineSharp.Protocol.Packets.Clientbound.Play.KeepAlivePacket; -namespace MineSharp.Protocol.Packets.Handlers; +namespace MineSharp.Protocol.Packets.Handlers.Client; internal class PlayPacketHandler : IPacketHandler { diff --git a/Components/MineSharp.Protocol/Packets/Handlers/Client/StatusPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/Client/StatusPacketHandler.cs index 8b7000ab..cbf63c06 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/Client/StatusPacketHandler.cs +++ b/Components/MineSharp.Protocol/Packets/Handlers/Client/StatusPacketHandler.cs @@ -1,6 +1,6 @@ -using MineSharp.Data.Protocol; +using MineSharp.Data.Protocol; -namespace MineSharp.Protocol.Packets.Handlers; +namespace MineSharp.Protocol.Packets.Handlers.Client; internal class StatusPacketHandler : IPacketHandler { From 8d4262e4cbfc010862779d69782a5fbfc83c1a4a Mon Sep 17 00:00:00 2001 From: qwqtoday Date: Sat, 1 Jun 2024 14:58:45 +0800 Subject: [PATCH 3/8] using server packet handlers if the client is a server client --- .../MineSharp.Protocol/MinecraftClient.cs | 46 +++++++++++++++---- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/Components/MineSharp.Protocol/MinecraftClient.cs b/Components/MineSharp.Protocol/MinecraftClient.cs index 16bad91d..711e5a51 100644 --- a/Components/MineSharp.Protocol/MinecraftClient.cs +++ b/Components/MineSharp.Protocol/MinecraftClient.cs @@ -15,6 +15,9 @@ using System.Net; using MineSharp.Protocol.Packets.Serverbound.Configuration; using Newtonsoft.Json.Linq; +using MineSharp.Protocol.Packets.Handlers; +using ClientPacketHandlers = MineSharp.Protocol.Packets.Handlers.Client; +using ServerPacketHandlers = MineSharp.Protocol.Packets.Handlers.Server; namespace MineSharp.Protocol; @@ -77,6 +80,10 @@ public sealed class MinecraftClient : IDisposable /// public event Events.ClientStringEvent? OnDisconnected; + /// + /// + /// + public readonly bool isServerClient; /// /// The MinecraftData object of this client @@ -118,7 +125,7 @@ public MinecraftClient( this.Data = data; this._packetQueue = new ConcurrentQueue(); this._cancellation = new CancellationTokenSource(); - this._internalPacketHandler = new HandshakePacketHandler(this); + this._internalPacketHandler = new ClientPacketHandlers.HandshakePacketHandler(this); this._packetHandlers = new Dictionary>(); this._packetWaiters = new Dictionary>(); this._gameJoinedTsc = new TaskCompletionSource(); @@ -136,6 +143,8 @@ public MinecraftClient( this.Hostname = hostnameOrIp; this.gameState = GameState.Handshaking; this.Settings = settings ?? ClientSettings.Default; + + this.isServerClient = false; } /// @@ -168,9 +177,12 @@ public async Task Connect(GameState nextState) this._stream = new MinecraftStream(this._client.GetStream(), this._useAnonymousNbt); this.StreamLoop(); + if (!isServerClient) + { Logger.Info("Connected, starting handshake..."); await HandshakeProtocol.PerformHandshake(this, nextState, this.Data); } + } catch (SocketException ex) { Logger.Error(ex, "Error while connecting"); @@ -265,14 +277,16 @@ internal void UpdateGameState(GameState next) { this.gameState = next; + if (!this.isServerClient) + { this._internalPacketHandler = next switch { - GameState.Handshaking => new HandshakePacketHandler(this), - GameState.Login => new LoginPacketHandler(this, this.Data), - GameState.Status => new StatusPacketHandler(this), - GameState.Configuration => new ConfigurationPacketHandler(this, this.Data), - GameState.Play => new PlayPacketHandler(this, this.Data), - _ => throw new UnreachableException() + GameState.Handshaking => new Packets.Handlers.Client.HandshakePacketHandler(this), + GameState.Login => new Packets.Handlers.Client.LoginPacketHandler(this, this.Data), + GameState.Status => new Packets.Handlers.Client.StatusPacketHandler(this), + GameState.Configuration => new Packets.Handlers.Client.ConfigurationPacketHandler(this, this.Data), + GameState.Play => new Packets.Handlers.Client.PlayPacketHandler(this, this.Data), + _ => throw new UnreachableException() }; if (next == GameState.Play) @@ -290,6 +304,22 @@ internal void UpdateGameState(GameState next) this.Settings.EnableTextFiltering, this.Settings.AllowServerListings)); } + } else + { + this._internalPacketHandler = next switch + { + GameState.Handshaking => new Packets.Handlers.Server.HandshakePacketHandler(this), + GameState.Login => new Packets.Handlers.Client.LoginPacketHandler(this, this.Data), + GameState.Status => new Packets.Handlers.Client.StatusPacketHandler(this), + GameState.Configuration => new Packets.Handlers.Client.ConfigurationPacketHandler(this, this.Data), + GameState.Play => new Packets.Handlers.Client.PlayPacketHandler(this, this.Data), + _ => throw new UnreachableException() + }; + + if (next == GameState.Play) + this._gameJoinedTsc.TrySetResult(); + + } } internal void EnableEncryption(byte[] key) @@ -351,7 +381,7 @@ private async Task ReceivePackets() { var buffer = this._stream!.ReadPacket(); var packetId = buffer.ReadVarInt(); - var packetType = this.Data.Protocol.GetPacketType(PacketFlow.Clientbound, this.gameState, packetId); + var packetType = this.Data.Protocol.GetPacketType(isServerClient ? PacketFlow.Serverbound : PacketFlow.Clientbound, this.gameState, packetId); if (this._bundlePackets) this._bundledPackets.Enqueue((packetType, buffer)); From 7eb8acd66f00ecd4a5c41b532bd4bf2a3b62354d Mon Sep 17 00:00:00 2001 From: qwqtoday Date: Sat, 1 Jun 2024 14:59:14 +0800 Subject: [PATCH 4/8] Making Session Optional --- Components/MineSharp.Protocol/MinecraftClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Components/MineSharp.Protocol/MinecraftClient.cs b/Components/MineSharp.Protocol/MinecraftClient.cs index 711e5a51..ed2610db 100644 --- a/Components/MineSharp.Protocol/MinecraftClient.cs +++ b/Components/MineSharp.Protocol/MinecraftClient.cs @@ -93,7 +93,7 @@ public sealed class MinecraftClient : IDisposable /// /// The Session object for this client /// - public readonly Session Session; + public readonly Session? Session; /// /// The Hostname of the minecraft server provided in the constructor From 67b005dbf209b97ffdc122cc68f41c3f73c12ce3 Mon Sep 17 00:00:00 2001 From: qwqtoday Date: Sat, 1 Jun 2024 15:00:04 +0800 Subject: [PATCH 5/8] Making constructor for server client --- .../MineSharp.Protocol/MinecraftClient.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/Components/MineSharp.Protocol/MinecraftClient.cs b/Components/MineSharp.Protocol/MinecraftClient.cs index ed2610db..2f17402d 100644 --- a/Components/MineSharp.Protocol/MinecraftClient.cs +++ b/Components/MineSharp.Protocol/MinecraftClient.cs @@ -147,6 +147,42 @@ public MinecraftClient( this.isServerClient = false; } + /// + /// Constructor for MinecraftClient that is used for MinecraftServer + /// + /// + /// + /// + /// + /// + /// + internal MinecraftClient( + TcpClient client, + IPAddress ipAddress, + MinecraftData data, + Session? session = null, + string? hostname = null, + ClientSettings? settings = null + ) + { + this.ip = ipAddress; + this.Data = data; + this.Session = session; + this.Hostname = hostname ?? ""; + this.Port = 25565; + this.Settings = settings ?? ClientSettings.Default; + this._client = client; + + this._packetQueue = new ConcurrentQueue(); + this._cancellation = new CancellationTokenSource(); + this._internalPacketHandler = new ServerPacketHandlers.HandshakePacketHandler(this); + this._packetHandlers = new Dictionary>(); + this._packetWaiters = new Dictionary>(); + this._gameJoinedTsc = new TaskCompletionSource(); + this._bundledPackets = new Queue<(PacketType, PacketBuffer)>(); + + this.isServerClient = true; + } /// /// Connects to the minecraft sever. /// From 89de7185db21ba8d42f26ca0485f2ed69f363568 Mon Sep 17 00:00:00 2001 From: qwqtoday Date: Sat, 1 Jun 2024 15:00:34 +0800 Subject: [PATCH 6/8] Adding the server handshake packet handler --- .../Handlers/Server/HandshakePacketHandler.cs | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 Components/MineSharp.Protocol/Packets/Handlers/Server/HandshakePacketHandler.cs diff --git a/Components/MineSharp.Protocol/Packets/Handlers/Server/HandshakePacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/Server/HandshakePacketHandler.cs new file mode 100644 index 00000000..4ce5d063 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Handlers/Server/HandshakePacketHandler.cs @@ -0,0 +1,46 @@ +using MineSharp.Data.Protocol; +using MineSharp.Protocol.Exceptions; +using MineSharp.Protocol.Packets.Handlers.Client; +using MineSharp.Protocol.Packets.Serverbound.Handshaking; + +namespace MineSharp.Protocol.Packets.Handlers.Server; + +internal class HandshakePacketHandler : IPacketHandler +{ + private MinecraftClient _client; + + public HandshakePacketHandler(MinecraftClient client) + { + _client = client; + } + + + public bool HandlesIncoming(PacketType type) { + return type switch + { + PacketType.SB_Handshake_SetProtocol => true, + _ => false + }; + } + + + public Task HandleIncoming(IPacket packet) + { + return packet switch + { + HandshakePacket handshakePacket => HandleHandshake(handshakePacket) + }; + } + + public Task HandleOutgoing(IPacket packet) + { + return Task.CompletedTask; + } + + + private Task HandleHandshake(HandshakePacket packet) + { + _client.UpdateGameState(packet.NextState); + return Task.CompletedTask; + } +} From 630e38eb6bc855ea912af27a6a57f80a2c822534 Mon Sep 17 00:00:00 2001 From: qwqtoday Date: Sat, 1 Jun 2024 15:00:50 +0800 Subject: [PATCH 7/8] adding the minecraft server class --- .../MineSharp.Protocol/MinecraftClient.cs | 41 +++++----- .../MineSharp.Protocol/MinecraftServer.cs | 77 +++++++++++++++++++ 2 files changed, 97 insertions(+), 21 deletions(-) create mode 100644 Components/MineSharp.Protocol/MinecraftServer.cs diff --git a/Components/MineSharp.Protocol/MinecraftClient.cs b/Components/MineSharp.Protocol/MinecraftClient.cs index 2f17402d..88bbd1d2 100644 --- a/Components/MineSharp.Protocol/MinecraftClient.cs +++ b/Components/MineSharp.Protocol/MinecraftClient.cs @@ -7,7 +7,6 @@ using MineSharp.Protocol.Exceptions; using MineSharp.Protocol.Packets; using MineSharp.Protocol.Packets.Clientbound.Status; -using MineSharp.Protocol.Packets.Handlers; using MineSharp.Protocol.Packets.Serverbound.Status; using NLog; using System.Diagnostics; @@ -215,9 +214,9 @@ public async Task Connect(GameState nextState) this.StreamLoop(); if (!isServerClient) { - Logger.Info("Connected, starting handshake..."); - await HandshakeProtocol.PerformHandshake(this, nextState, this.Data); - } + Logger.Info("Connected, starting handshake..."); + await HandshakeProtocol.PerformHandshake(this, nextState, this.Data); + } } catch (SocketException ex) { @@ -315,31 +314,31 @@ internal void UpdateGameState(GameState next) if (!this.isServerClient) { - this._internalPacketHandler = next switch - { + this._internalPacketHandler = next switch + { GameState.Handshaking => new Packets.Handlers.Client.HandshakePacketHandler(this), GameState.Login => new Packets.Handlers.Client.LoginPacketHandler(this, this.Data), GameState.Status => new Packets.Handlers.Client.StatusPacketHandler(this), GameState.Configuration => new Packets.Handlers.Client.ConfigurationPacketHandler(this, this.Data), GameState.Play => new Packets.Handlers.Client.PlayPacketHandler(this, this.Data), _ => throw new UnreachableException() - }; + }; - if (next == GameState.Play) - this._gameJoinedTsc.TrySetResult(); + if (next == GameState.Play) + this._gameJoinedTsc.TrySetResult(); - if (next == GameState.Configuration) - { - this.SendPacket(new ClientInformationPacket( - this.Settings.Locale, - this.Settings.ViewDistance, - (int)this.Settings.ChatMode, - this.Settings.ColoredChat, - this.Settings.DisplayedSkinParts, - (int)this.Settings.MainHand, - this.Settings.EnableTextFiltering, - this.Settings.AllowServerListings)); - } + if (next == GameState.Configuration) + { + this.SendPacket(new ClientInformationPacket( + this.Settings.Locale, + this.Settings.ViewDistance, + (int)this.Settings.ChatMode, + this.Settings.ColoredChat, + this.Settings.DisplayedSkinParts, + (int)this.Settings.MainHand, + this.Settings.EnableTextFiltering, + this.Settings.AllowServerListings)); + } } else { this._internalPacketHandler = next switch diff --git a/Components/MineSharp.Protocol/MinecraftServer.cs b/Components/MineSharp.Protocol/MinecraftServer.cs new file mode 100644 index 00000000..7c9dbec6 --- /dev/null +++ b/Components/MineSharp.Protocol/MinecraftServer.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading.Tasks; +using MineSharp.Auth; +using MineSharp.Core.Common.Protocol; +using MineSharp.Data; +using NLog; +using Org.BouncyCastle.Crypto.Tls; + +namespace MineSharp.Protocol; + +/// +/// Minecraft server class +/// +public sealed class MinecraftServer +{ + /// + /// The latest version supported + /// + public const string LATEST_SUPPORTED_VERSION = "1.20.4"; + + private static readonly ILogger Logger = LogManager.GetCurrentClassLogger(); + + private readonly MinecraftData Data; + + private readonly IPAddress _address; + private readonly ushort _port; + private TcpListener? _listener; + + internal readonly MinecraftApi? Api; + + + /// + /// The constructor for the MinecraftServer class + /// + public MinecraftServer( + MinecraftData data, + IPAddress address, + ushort port) + { + this.Data = data; + this._address = address; + this._port = port; + } + + /// + /// Start the Minecraft server + /// + public void Start() + { + _listener = new TcpListener(_address, _port); + + _listener.Start(); + + Task.Run(ListenForNewClients); + } + + private void ListenForNewClients() + { + while (true) + { + using TcpClient client = _listener!.AcceptTcpClient(); + + Task.Run(() => HandleNewClient(client)); + } + } + + private void HandleNewClient(TcpClient client) + { + MinecraftClient minecraftClient = new MinecraftClient(client, _address, Data); + minecraftClient.UpdateGameState(GameState.Handshaking); + } +} From b25f72eb4708acfa2c30d8dc18a8de945482552b Mon Sep 17 00:00:00 2001 From: qwqtoday Date: Sun, 2 Jun 2024 21:22:45 +0800 Subject: [PATCH 8/8] add other handlers, (they are just copied from client handlers) --- .../MineSharp.Protocol/MinecraftClient.cs | 35 ++--- .../Server/ConfigurationPacketHandler.cs | 75 +++++++++++ .../Handlers/Server/HandshakePacketHandler.cs | 6 + .../Handlers/Server/LoginPacketHandler.cs | 123 ++++++++++++++++++ .../Handlers/Server/PlayPacketHandler.cs | 63 +++++++++ .../Handlers/Server/StatusPacketHandler.cs | 17 +++ 6 files changed, 304 insertions(+), 15 deletions(-) create mode 100644 Components/MineSharp.Protocol/Packets/Handlers/Server/ConfigurationPacketHandler.cs create mode 100644 Components/MineSharp.Protocol/Packets/Handlers/Server/LoginPacketHandler.cs create mode 100644 Components/MineSharp.Protocol/Packets/Handlers/Server/PlayPacketHandler.cs create mode 100644 Components/MineSharp.Protocol/Packets/Handlers/Server/StatusPacketHandler.cs diff --git a/Components/MineSharp.Protocol/MinecraftClient.cs b/Components/MineSharp.Protocol/MinecraftClient.cs index 88bbd1d2..ca8fda3e 100644 --- a/Components/MineSharp.Protocol/MinecraftClient.cs +++ b/Components/MineSharp.Protocol/MinecraftClient.cs @@ -87,7 +87,7 @@ public sealed class MinecraftClient : IDisposable /// /// The MinecraftData object of this client /// - public readonly MinecraftData Data; + public MinecraftData Data { get; private set; } /// /// The Session object for this client @@ -97,12 +97,12 @@ public sealed class MinecraftClient : IDisposable /// /// The Hostname of the minecraft server provided in the constructor /// - public readonly string Hostname; + public string Hostname { get; private set; } /// /// The Port of the minecraft server /// - public readonly ushort Port; + public ushort Port { get; private set; } /// /// The clients settings @@ -316,12 +316,12 @@ internal void UpdateGameState(GameState next) { this._internalPacketHandler = next switch { - GameState.Handshaking => new Packets.Handlers.Client.HandshakePacketHandler(this), - GameState.Login => new Packets.Handlers.Client.LoginPacketHandler(this, this.Data), - GameState.Status => new Packets.Handlers.Client.StatusPacketHandler(this), - GameState.Configuration => new Packets.Handlers.Client.ConfigurationPacketHandler(this, this.Data), - GameState.Play => new Packets.Handlers.Client.PlayPacketHandler(this, this.Data), - _ => throw new UnreachableException() + GameState.Handshaking => new ClientPacketHandlers.HandshakePacketHandler(this), + GameState.Login => new ClientPacketHandlers.LoginPacketHandler(this, this.Data), + GameState.Status => new ClientPacketHandlers.StatusPacketHandler(this), + GameState.Configuration => new ClientPacketHandlers.ConfigurationPacketHandler(this, this.Data), + GameState.Play => new ClientPacketHandlers.PlayPacketHandler(this, this.Data), + _ => throw new UnreachableException() }; if (next == GameState.Play) @@ -343,12 +343,12 @@ internal void UpdateGameState(GameState next) { this._internalPacketHandler = next switch { - GameState.Handshaking => new Packets.Handlers.Server.HandshakePacketHandler(this), - GameState.Login => new Packets.Handlers.Client.LoginPacketHandler(this, this.Data), - GameState.Status => new Packets.Handlers.Client.StatusPacketHandler(this), - GameState.Configuration => new Packets.Handlers.Client.ConfigurationPacketHandler(this, this.Data), - GameState.Play => new Packets.Handlers.Client.PlayPacketHandler(this, this.Data), - _ => throw new UnreachableException() + GameState.Handshaking => new ServerPacketHandlers.HandshakePacketHandler(this), + GameState.Login => new ServerPacketHandlers.LoginPacketHandler(this, this.Data), + GameState.Status => new ServerPacketHandlers.StatusPacketHandler(this), + GameState.Configuration => new ServerPacketHandlers.ConfigurationPacketHandler(this, this.Data), + GameState.Play => new ServerPacketHandlers.PlayPacketHandler(this, this.Data), + _ => throw new UnreachableException() }; if (next == GameState.Play) @@ -545,6 +545,11 @@ private async Task HandleOutgoingPacket(IPacket packet) }); } + internal void HandshakeUpdateHostAndPort(string host, ushort port) + { + Hostname = host; + Port = port; + } private Task InvokeReceivePacketAsync(IPacket packet) { return Task.Run(() => this.OnPacketReceived?.Invoke(this, packet)); diff --git a/Components/MineSharp.Protocol/Packets/Handlers/Server/ConfigurationPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/Server/ConfigurationPacketHandler.cs new file mode 100644 index 00000000..997c1c5e --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Handlers/Server/ConfigurationPacketHandler.cs @@ -0,0 +1,75 @@ +using MineSharp.Core.Common.Protocol; +using MineSharp.Data; +using MineSharp.Data.Protocol; +using MineSharp.Protocol.Packets.Clientbound.Configuration; +using NLog; + +namespace MineSharp.Protocol.Packets.Handlers.Server; + +internal class ConfigurationPacketHandler : IPacketHandler +{ + private static readonly ILogger Logger = LogManager.GetCurrentClassLogger(); + + private readonly MinecraftClient _client; + private readonly MinecraftData _data; + + public ConfigurationPacketHandler(MinecraftClient client, MinecraftData data) + { + this._client = client; + this._data = data; + } + + public Task HandleIncoming(IPacket packet) + { + return packet switch + { + DisconnectPacket disconnect => HandleDisconnect(disconnect), + FinishConfigurationPacket finishConfiguration => HandleFinishConfiguration(finishConfiguration), + KeepAlivePacket keepAlive => HandleKeepAlive(keepAlive), + PingPacket ping => HandlePing(ping), + + _ => Task.CompletedTask + }; + } + + public Task HandleOutgoing(IPacket packet) + { + if (packet is Serverbound.Configuration.FinishConfigurationPacket) + { + this._client.UpdateGameState(GameState.Play); + } + + return Task.CompletedTask; + } + + public bool HandlesIncoming(PacketType type) + => type is PacketType.CB_Configuration_Disconnect + or PacketType.CB_Configuration_FinishConfiguration + or PacketType.CB_Configuration_KeepAlive + or PacketType.CB_Configuration_Ping; + + + private Task HandleDisconnect(DisconnectPacket packet) + { + _ = Task.Run(() => this._client.Disconnect(packet.Reason.Json)); + return Task.CompletedTask; + } + + private Task HandleFinishConfiguration(FinishConfigurationPacket packet) + { + _ = this._client.SendPacket(new Serverbound.Configuration.FinishConfigurationPacket()); + return Task.CompletedTask; + } + + private Task HandleKeepAlive(KeepAlivePacket packet) + { + this._client.SendPacket(new Serverbound.Configuration.KeepAlivePacket(packet.KeepAliveId)); + return Task.CompletedTask; + } + + private Task HandlePing(PingPacket packet) + { + this._client.SendPacket(new Serverbound.Configuration.PongPacket(packet.Id)); + return Task.CompletedTask; + } +} diff --git a/Components/MineSharp.Protocol/Packets/Handlers/Server/HandshakePacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/Server/HandshakePacketHandler.cs index 4ce5d063..57582afa 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/Server/HandshakePacketHandler.cs +++ b/Components/MineSharp.Protocol/Packets/Handlers/Server/HandshakePacketHandler.cs @@ -40,6 +40,12 @@ public Task HandleOutgoing(IPacket packet) private Task HandleHandshake(HandshakePacket packet) { + if (_client.Data.Version.Protocol != packet.ProtocolVersion) + { + _client.Disconnect(); + return Task.CompletedTask; + } + _client.HandshakeUpdateHostAndPort(packet.Host, packet.Port); _client.UpdateGameState(packet.NextState); return Task.CompletedTask; } diff --git a/Components/MineSharp.Protocol/Packets/Handlers/Server/LoginPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/Server/LoginPacketHandler.cs new file mode 100644 index 00000000..aa302cff --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Handlers/Server/LoginPacketHandler.cs @@ -0,0 +1,123 @@ +using MineSharp.Auth.Exceptions; +using MineSharp.Core.Common; +using MineSharp.Core.Common.Protocol; +using MineSharp.Data; +using MineSharp.Data.Protocol; +using MineSharp.Protocol.Cryptography; +using MineSharp.Protocol.Packets.Clientbound.Login; +using MineSharp.Protocol.Packets.Serverbound.Login; +using NLog; +using System.Diagnostics; +using System.Security.Cryptography; + +namespace MineSharp.Protocol.Packets.Handlers.Server; + +internal class LoginPacketHandler : IPacketHandler +{ + private static readonly ILogger Logger = LogManager.GetCurrentClassLogger(); + + private readonly MinecraftClient _client; + private readonly MinecraftData _data; + + public LoginPacketHandler(MinecraftClient client, MinecraftData data) + { + this._client = client; + this._data = data; + } + + public Task HandleIncoming(IPacket packet) + { + return packet switch + { + DisconnectPacket disconnect => HandleDisconnect(disconnect), + EncryptionRequestPacket encryption => HandleEncryptionRequest(encryption), + SetCompressionPacket compression => HandleSetCompression(compression), + LoginSuccessPacket success => HandleLoginSuccess(success), + _ => throw new UnreachableException() + }; + } + + public Task HandleOutgoing(IPacket packet) + => Task.CompletedTask; + + public bool HandlesIncoming(PacketType type) + => type is PacketType.CB_Login_Disconnect + or PacketType.CB_Login_EncryptionBegin + or PacketType.CB_Login_Compress + or PacketType.CB_Login_LoginPluginRequest + or PacketType.CB_Login_Success; + + private Task HandleDisconnect(DisconnectPacket packet) + { + _ = Task.Run(() => this._client.Disconnect(packet.Reason.Json)); + return Task.CompletedTask; + } + + private async Task HandleEncryptionRequest(EncryptionRequestPacket packet) + { + var aes = Aes.Create(); + aes.KeySize = 128; + aes.GenerateKey(); + + var hex = EncryptionHelper.ComputeHash(packet.ServerId, aes.Key, packet.PublicKey); + + // Authenticate + if (this._client.Session.OnlineSession) + { + if (!await this._client.Api!.JoinServer(hex, this._client.Session.SessionToken, this._client.Session.UUID)) + { + throw new MineSharpAuthException("Error trying to authenticate with Mojang"); + } + } + + var rsa = EncryptionHelper.DecodePublicKey(packet.PublicKey!); + if (rsa == null) + throw new Exception("Could not decode public key"); + + var sharedSecret = rsa.Encrypt(aes.Key, RSAEncryptionPadding.Pkcs1); + var encVerToken = rsa.Encrypt(packet.VerifyToken!, RSAEncryptionPadding.Pkcs1); + + EncryptionResponsePacket response; + if (ProtocolVersion.IsBetween(this._data.Version.Protocol, ProtocolVersion.V_1_19, ProtocolVersion.V_1_19_2) + && this._client.Session.OnlineSession + && this._client.Session.Certificate is not null) + { + var salt = (long)RandomNumberGenerator.GetInt32(int.MaxValue) << 32 | (uint)RandomNumberGenerator.GetInt32(int.MaxValue); + + var signData = new PacketBuffer(this._data.Version.Protocol >= ProtocolVersion.V_1_20_2); + signData.WriteBytes(packet.VerifyToken); + signData.WriteLong(salt); + + var signed = this._client.Session.Certificate.RsaPrivate.SignData(signData.GetBuffer(), HashAlgorithmName.SHA256, + RSASignaturePadding.Pkcs1); + var crypto = new EncryptionResponsePacket.CryptoContainer(salt, signed); + + response = new EncryptionResponsePacket(sharedSecret, null, crypto); + } + else + response = new EncryptionResponsePacket(sharedSecret, encVerToken, null); + + _ = this._client.SendPacket(response) + .ContinueWith(_ => this._client.EnableEncryption(aes.Key)); + } + + private Task HandleSetCompression(SetCompressionPacket packet) + { + Logger.Debug($"Enabling compression, threshold = {packet.Threshold}."); + this._client.SetCompression(packet.Threshold); + return Task.CompletedTask; + } + + private Task HandleLoginSuccess(LoginSuccessPacket packet) + { + if (this._data.Version.Protocol < ProtocolVersion.V_1_20_2) + { + this._client.UpdateGameState(GameState.Play); + return Task.CompletedTask; + } + + _ = this._client.SendPacket(new AcknowledgeLoginPacket()) + .ContinueWith(_ => this._client.UpdateGameState(GameState.Configuration)); + return Task.CompletedTask; + } +} diff --git a/Components/MineSharp.Protocol/Packets/Handlers/Server/PlayPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/Server/PlayPacketHandler.cs new file mode 100644 index 00000000..c4caa21e --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Handlers/Server/PlayPacketHandler.cs @@ -0,0 +1,63 @@ +using MineSharp.Data; +using MineSharp.Data.Protocol; +using MineSharp.Protocol.Packets.Clientbound.Play; +using MineSharp.Protocol.Packets.Serverbound.Play; +using KeepAlivePacket = MineSharp.Protocol.Packets.Clientbound.Play.KeepAlivePacket; + +namespace MineSharp.Protocol.Packets.Handlers.Server; + +internal class PlayPacketHandler : IPacketHandler +{ + private MinecraftClient _client; + private MinecraftData _data; + + public PlayPacketHandler(MinecraftClient client, MinecraftData data) + { + this._client = client; + this._data = data; + } + + public Task HandleIncoming(IPacket packet) + { + return packet switch + { + KeepAlivePacket keepAlive => HandleKeepAlive(keepAlive), + BundleDelimiterPacket bundleDelimiter => HandleBundleDelimiter(bundleDelimiter), + PingPacket ping => HandlePing(ping), + DisconnectPacket disconnect => HandleDisconnect(disconnect), + _ => Task.CompletedTask + }; + } + + public Task HandleOutgoing(IPacket packet) + { + return Task.CompletedTask; + } + + public bool HandlesIncoming(PacketType type) + => type is PacketType.CB_Play_KeepAlive or PacketType.CB_Play_BundleDelimiter or PacketType.CB_Play_Ping or PacketType.CB_Play_KickDisconnect; + + private Task HandleKeepAlive(KeepAlivePacket packet) + { + this._client.SendPacket(new Serverbound.Play.KeepAlivePacket(packet.KeepAliveId)); + return Task.CompletedTask; + } + + private Task HandleBundleDelimiter(BundleDelimiterPacket bundleDelimiter) + { + this._client.HandleBundleDelimiter(); + return Task.CompletedTask; + } + + private Task HandlePing(PingPacket ping) + { + this._client.SendPacket(new PongPacket(ping.Id)); + return Task.CompletedTask; + } + + private Task HandleDisconnect(DisconnectPacket packet) + { + _ = Task.Run(() => this._client.Disconnect(packet.Reason.Json)); + return Task.CompletedTask; + } +} diff --git a/Components/MineSharp.Protocol/Packets/Handlers/Server/StatusPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/Server/StatusPacketHandler.cs new file mode 100644 index 00000000..577f20e4 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Handlers/Server/StatusPacketHandler.cs @@ -0,0 +1,17 @@ +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Handlers.Server; + +internal class StatusPacketHandler : IPacketHandler +{ + private MinecraftClient _client; + + public StatusPacketHandler(MinecraftClient client) + { + this._client = client; + } + + public Task HandleIncoming(IPacket packet) => Task.CompletedTask; + public Task HandleOutgoing(IPacket packet) => Task.CompletedTask; + public bool HandlesIncoming(PacketType type) => false; +}