diff --git a/Components/MineSharp.Protocol/MinecraftClient.cs b/Components/MineSharp.Protocol/MinecraftClient.cs index 16bad91d..ca8fda3e 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; @@ -15,6 +14,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,26 +79,30 @@ public sealed class MinecraftClient : IDisposable /// public event Events.ClientStringEvent? OnDisconnected; + /// + /// + /// + public readonly bool isServerClient; /// /// The MinecraftData object of this client /// - public readonly MinecraftData Data; + public MinecraftData Data { get; private set; } /// /// The Session object for this client /// - public readonly Session Session; + public readonly Session? Session; /// /// 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 @@ -118,7 +124,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,8 +142,46 @@ public MinecraftClient( this.Hostname = hostnameOrIp; this.gameState = GameState.Handshaking; this.Settings = settings ?? ClientSettings.Default; + + 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. /// @@ -168,8 +212,11 @@ public async Task Connect(GameState nextState) this._stream = new MinecraftStream(this._client.GetStream(), this._useAnonymousNbt); this.StreamLoop(); - Logger.Info("Connected, starting handshake..."); - await HandshakeProtocol.PerformHandshake(this, nextState, this.Data); + if (!isServerClient) + { + Logger.Info("Connected, starting handshake..."); + await HandshakeProtocol.PerformHandshake(this, nextState, this.Data); + } } catch (SocketException ex) { @@ -265,30 +312,48 @@ internal void UpdateGameState(GameState next) { this.gameState = next; - this._internalPacketHandler = next switch + if (!this.isServerClient) { - 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() - }; - - if (next == GameState.Play) - this._gameJoinedTsc.TrySetResult(); - - if (next == GameState.Configuration) + this._internalPacketHandler = next switch + { + 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) + 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)); + } + } else { - 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)); + this._internalPacketHandler = next switch + { + 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) + this._gameJoinedTsc.TrySetResult(); + } } @@ -351,7 +416,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)); @@ -480,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/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); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Handlers/ConfigurationPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/Client/ConfigurationPacketHandler.cs similarity index 96% rename from Components/MineSharp.Protocol/Packets/Handlers/ConfigurationPacketHandler.cs rename to Components/MineSharp.Protocol/Packets/Handlers/Client/ConfigurationPacketHandler.cs index c609bcd8..1bf99702 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/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/HandshakePacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/Client/HandshakePacketHandler.cs similarity index 91% rename from Components/MineSharp.Protocol/Packets/Handlers/HandshakePacketHandler.cs rename to Components/MineSharp.Protocol/Packets/Handlers/Client/HandshakePacketHandler.cs index fbb1c15a..e3354f0a 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/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/LoginPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/Client/LoginPacketHandler.cs similarity index 98% rename from Components/MineSharp.Protocol/Packets/Handlers/LoginPacketHandler.cs rename to Components/MineSharp.Protocol/Packets/Handlers/Client/LoginPacketHandler.cs index bad5bb89..807eaad8 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/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/PlayPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/Client/PlayPacketHandler.cs similarity index 97% rename from Components/MineSharp.Protocol/Packets/Handlers/PlayPacketHandler.cs rename to Components/MineSharp.Protocol/Packets/Handlers/Client/PlayPacketHandler.cs index dc848be1..01428059 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/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/StatusPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/Client/StatusPacketHandler.cs similarity index 82% rename from Components/MineSharp.Protocol/Packets/Handlers/StatusPacketHandler.cs rename to Components/MineSharp.Protocol/Packets/Handlers/Client/StatusPacketHandler.cs index 8b7000ab..cbf63c06 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/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 { 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 new file mode 100644 index 00000000..57582afa --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Handlers/Server/HandshakePacketHandler.cs @@ -0,0 +1,52 @@ +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) + { + 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; +}