diff --git a/src/API/Events/Authentication/AuthenticationCompletedEvent.cs b/src/API/Events/Authentication/AuthenticationCompletedEvent.cs new file mode 100644 index 0000000..b6133ab --- /dev/null +++ b/src/API/Events/Authentication/AuthenticationCompletedEvent.cs @@ -0,0 +1,9 @@ +using Void.Proxy.API.Links; + +namespace Void.Proxy.API.Events.Authentication; + +public class AuthenticationCompletedEvent : IEvent +{ + public required ILink Link { get; init; } + public required AuthenticationSide Side { get; init; } +} \ No newline at end of file diff --git a/src/API/Events/Authentication/AuthenticationFailedEvent.cs b/src/API/Events/Authentication/AuthenticationFailedEvent.cs new file mode 100644 index 0000000..683f2b3 --- /dev/null +++ b/src/API/Events/Authentication/AuthenticationFailedEvent.cs @@ -0,0 +1,9 @@ +using Void.Proxy.API.Links; + +namespace Void.Proxy.API.Events.Authentication; + +public class AuthenticationFailed : IEvent +{ + public required ILink Link { get; init; } + public required AuthenticationSide Side { get; init; } +} \ No newline at end of file diff --git a/src/API/Events/Authentication/AuthenticationSide.cs b/src/API/Events/Authentication/AuthenticationSide.cs new file mode 100644 index 0000000..2f171a4 --- /dev/null +++ b/src/API/Events/Authentication/AuthenticationSide.cs @@ -0,0 +1,7 @@ +namespace Void.Proxy.API.Events.Authentication; + +public enum AuthenticationSide +{ + Proxy, + Server +} \ No newline at end of file diff --git a/src/API/Events/Authentication/AuthenticationStartedEvent.cs b/src/API/Events/Authentication/AuthenticationStartedEvent.cs new file mode 100644 index 0000000..0431f04 --- /dev/null +++ b/src/API/Events/Authentication/AuthenticationStartedEvent.cs @@ -0,0 +1,9 @@ +using Void.Proxy.API.Links; + +namespace Void.Proxy.API.Events.Authentication; + +public class AuthenticationStartedEvent : IEvent +{ + public required ILink Link { get; init; } + public required AuthenticationSide Side { get; init; } +} \ No newline at end of file diff --git a/src/API/Events/Authentication/AuthenticationStartingEvent.cs b/src/API/Events/Authentication/AuthenticationStartingEvent.cs new file mode 100644 index 0000000..d03faf6 --- /dev/null +++ b/src/API/Events/Authentication/AuthenticationStartingEvent.cs @@ -0,0 +1,9 @@ +using Void.Proxy.API.Links; + +namespace Void.Proxy.API.Events.Authentication; + +public class AuthenticationStartingEvent : IEventWithResult +{ + public required ILink Link { get; init; } + public AuthenticationSide Result { get; set; } = AuthenticationSide.Proxy; +} \ No newline at end of file diff --git a/src/API/Links/ILink.cs b/src/API/Links/ILink.cs index 9bf355c..5ab57f3 100644 --- a/src/API/Links/ILink.cs +++ b/src/API/Links/ILink.cs @@ -12,4 +12,6 @@ public interface ILink : IEventListener, IAsyncDisposable public IMinecraftChannel PlayerChannel { get; } public IMinecraftChannel ServerChannel { get; } public bool IsAlive { get; } + + public ValueTask StartAsync(CancellationToken cancellationToken); } \ No newline at end of file diff --git a/src/API/Network/IO/Channels/IMinecraftChannel.cs b/src/API/Network/IO/Channels/IMinecraftChannel.cs index ff68025..c3fafe0 100644 --- a/src/API/Network/IO/Channels/IMinecraftChannel.cs +++ b/src/API/Network/IO/Channels/IMinecraftChannel.cs @@ -13,7 +13,6 @@ public interface IMinecraftChannel : IDisposable, IAsyncDisposable public bool IsConfigured { get; } public bool IsPaused { get; } - public bool IsRedirectionSupported { get; } public void Add() where T : class, IMinecraftStream, new(); public void Add(T stream) where T : class, IMinecraftStream; diff --git a/src/API/Network/IO/Channels/Services/IMinecraftChannelBuilderService.cs b/src/API/Network/IO/Channels/Services/IMinecraftChannelBuilderService.cs index fcb954e..c24f608 100644 --- a/src/API/Network/IO/Channels/Services/IMinecraftChannelBuilderService.cs +++ b/src/API/Network/IO/Channels/Services/IMinecraftChannelBuilderService.cs @@ -5,6 +5,8 @@ namespace Void.Proxy.API.Network.IO.Channels.Services; public interface IMinecraftChannelBuilderService { + public bool IsFallbackBuilder { get; } + public ValueTask SearchChannelBuilderAsync(IPlayer player, CancellationToken cancellationToken = default); public ValueTask BuildPlayerChannelAsync(IPlayer player, CancellationToken cancellationToken = default); diff --git a/src/API/Network/Protocol/ProtocolVersion.cs b/src/API/Network/Protocol/ProtocolVersion.cs index 5be4a14..4f34bba 100644 --- a/src/API/Network/Protocol/ProtocolVersion.cs +++ b/src/API/Network/Protocol/ProtocolVersion.cs @@ -53,7 +53,7 @@ public ProtocolVersion(int version, params string[] names) Names = names; if (!Mapping.TryAdd(version, this)) - throw new InvalidOperationException($"ProtocolVersion {version} already registered, use Search() instead"); + throw new InvalidOperationException($"ProtocolVersion {version} already registered, use Get() instead"); } public static ProtocolVersion Latest => Mapping.MaxBy(kv => kv.Key).Value; diff --git a/src/API/Players/PlayerExtensions.cs b/src/API/Players/PlayerExtensions.cs index fe0096b..d186d7f 100644 --- a/src/API/Players/PlayerExtensions.cs +++ b/src/API/Players/PlayerExtensions.cs @@ -24,6 +24,12 @@ public static async ValueTask GetChannelAsync(this IPlayer pl return player.Context.Channel; } + public static async ValueTask IsProtocolSupportedAsync(this IPlayer player, CancellationToken cancellationToken = default) + { + var channelBuilder = await player.GetChannelBuilderAsync(cancellationToken); + return !channelBuilder.IsFallbackBuilder; + } + private static async ValueTask GetChannelBuilderAsync(this IPlayer player, CancellationToken cancellationToken = default) { var channelBuilder = player.Context.Services.GetRequiredService(); diff --git a/src/Common/Network/IO/Channels/Services/SimpleChannelBuilderService.cs b/src/Common/Network/IO/Channels/Services/SimpleChannelBuilderService.cs index 2c3edd4..e0642b3 100644 --- a/src/Common/Network/IO/Channels/Services/SimpleChannelBuilderService.cs +++ b/src/Common/Network/IO/Channels/Services/SimpleChannelBuilderService.cs @@ -17,12 +17,14 @@ public class SimpleChannelBuilderService(ILogger lo public const int MaxHandshakeSize = 4096; private Memory _buffer = Memory.Empty; - private ChannelBuilder _builder = (_, networkStream, _) => ValueTask.FromResult(new SimpleChannel(new SimpleNetworkStream(networkStream))); - private bool _found; + private ChannelBuilder _builder = FallbackBuilder; + private bool _executed; + + public bool IsFallbackBuilder { get; private set; } public async ValueTask SearchChannelBuilderAsync(IPlayer player, CancellationToken cancellationToken = default) { - if (_found) + if (_executed) return; logger.LogTrace("Searching for channel builder for a {Player} player", player); @@ -35,12 +37,17 @@ public async ValueTask SearchChannelBuilderAsync(IPlayer player, CancellationTok await events.ThrowAsync(searchProtocolCodec, cancellationToken); if (searchProtocolCodec.Result is not null) + { _builder = searchProtocolCodec.Result; + } else + { + IsFallbackBuilder = true; logger.LogWarning("Channel builder not found for a {Player} player", player); + } _buffer = searchProtocolCodec.Buffer; - _found = true; + _executed = true; } public async ValueTask BuildPlayerChannelAsync(IPlayer player, CancellationToken cancellationToken = default) @@ -80,4 +87,9 @@ private async ValueTask BuildChannelAsync(Direction direction return channel; } + + private static ValueTask FallbackBuilder(Direction direction, NetworkStream networkStream, CancellationToken cancellationToken) + { + return ValueTask.FromResult(new SimpleChannel(new SimpleNetworkStream(networkStream))); + } } \ No newline at end of file diff --git a/src/Common/Network/IO/Channels/SimpleChannel.cs b/src/Common/Network/IO/Channels/SimpleChannel.cs index 82e8e40..a44a3b6 100644 --- a/src/Common/Network/IO/Channels/SimpleChannel.cs +++ b/src/Common/Network/IO/Channels/SimpleChannel.cs @@ -21,7 +21,6 @@ public class SimpleChannel(IMinecraftStreamBase head) : IMinecraftChannel public bool IsConfigured => head is IMinecraftStream; public bool IsPaused => _pause is { Task.IsCompleted: false }; - public bool IsRedirectionSupported => false; public void Add() where T : class, IMinecraftStream, new() { diff --git a/src/Platform/Links/Link.cs b/src/Platform/Links/Link.cs index dae0e40..369e477 100644 --- a/src/Platform/Links/Link.cs +++ b/src/Platform/Links/Link.cs @@ -11,50 +11,44 @@ namespace Void.Proxy.Links; -public class Link : ILink +public class Link(IPlayer player, IServer server, IMinecraftChannel playerChannel, IMinecraftChannel serverChannel, ILogger logger, IEventService events) : ILink { - private readonly CancellationTokenSource _ctsPlayerToServer; - private readonly CancellationTokenSource _ctsPlayerToServerForce; - private readonly CancellationTokenSource _ctsServerToPlayer; - private readonly CancellationTokenSource _ctsServerToPlayerForce; - private readonly IEventService _events; - private readonly AsyncLock _lock; - private readonly ILogger _logger; - private readonly Task _playerToServerTask; - private readonly Task _serverToPlayerTask; - - public Link(IPlayer player, IServer server, IMinecraftChannel playerChannel, IMinecraftChannel serverChannel, ILogger logger, IEventService events) - { - Player = player; - Server = server; - PlayerChannel = playerChannel; - ServerChannel = serverChannel; + private readonly CancellationTokenSource _ctsPlayerToServer = new(); + private readonly CancellationTokenSource _ctsPlayerToServerForce = new(); + private readonly CancellationTokenSource _ctsServerToPlayer = new(); + private readonly CancellationTokenSource _ctsServerToPlayerForce = new(); + private readonly AsyncLock _lock = new(); + + private Task? _playerToServerTask; + private Task? _serverToPlayerTask; - _logger = logger; - _events = events; + public IPlayer Player { get; init; } = player; + public IServer Server { get; init; } = server; + public IMinecraftChannel PlayerChannel { get; init; } = playerChannel; + public IMinecraftChannel ServerChannel { get; init; } = serverChannel; - _lock = new AsyncLock(); + public bool IsAlive => _playerToServerTask?.Status == TaskStatus.Running && _serverToPlayerTask?.Status == TaskStatus.Running; + + public async ValueTask StartAsync(CancellationToken cancellationToken) + { + if (this is { _playerToServerTask: not null } or { _serverToPlayerTask: not null }) + throw new InvalidOperationException("Link was already started"); - _ctsPlayerToServer = new CancellationTokenSource(); - _ctsPlayerToServerForce = new CancellationTokenSource(); - _ctsServerToPlayer = new CancellationTokenSource(); - _ctsServerToPlayerForce = new CancellationTokenSource(); + await events.ThrowAsync(new LinkStartingEvent { Link = this }, cancellationToken); + + events.RegisterListeners(this); _playerToServerTask = ExecuteAsync(PlayerChannel, ServerChannel, Direction.Serverbound, _ctsPlayerToServer.Token, _ctsPlayerToServerForce.Token); _serverToPlayerTask = ExecuteAsync(ServerChannel, PlayerChannel, Direction.Clientbound, _ctsServerToPlayer.Token, _ctsServerToPlayerForce.Token); - } - - public IPlayer Player { get; init; } - public IServer Server { get; init; } - public IMinecraftChannel PlayerChannel { get; init; } - public IMinecraftChannel ServerChannel { get; init; } - public bool IsAlive => _playerToServerTask.Status == TaskStatus.Running && _serverToPlayerTask.Status == TaskStatus.Running; + logger.LogInformation("Started forwarding {Link} traffic", this); + await events.ThrowAsync(new LinkStartedEvent { Link = this }, cancellationToken); + } public async ValueTask DisposeAsync() { // if the player does not support redirections, that's the end for him - if (!PlayerChannel.IsRedirectionSupported) + if (true /*!PlayerChannel.IsRedirectionSupported*/) { PlayerChannel.Close(); await PlayerChannel.DisposeAsync(); @@ -63,42 +57,45 @@ public async ValueTask DisposeAsync() ServerChannel.Close(); await ServerChannel.DisposeAsync(); - if (await WaitWithTimeout(_serverToPlayerTask)) + if (_serverToPlayerTask is not null) { - _logger.LogTrace("Timed out waiting Server {Server} disconnection from Player {Player}, closing manually", Server, Player); - await _ctsServerToPlayer.CancelAsync(); - if (await WaitWithTimeout(_serverToPlayerTask)) { - _logger.LogTrace("Timed out waiting Server {Server} disconnection from Player {Player} manually, closing forcefully", Server, Player); - await _ctsServerToPlayerForce.CancelAsync(); + logger.LogTrace("Timed out waiting Server {Server} disconnection from Player {Player}, closing manually", Server, Player); + await _ctsServerToPlayer.CancelAsync(); if (await WaitWithTimeout(_serverToPlayerTask)) - throw new Exception($"Cannot dispose Link {this} (player=>server)"); + { + logger.LogTrace("Timed out waiting Server {Server} disconnection from Player {Player} manually, closing forcefully", Server, Player); + await _ctsServerToPlayerForce.CancelAsync(); + + if (await WaitWithTimeout(_serverToPlayerTask)) + throw new Exception($"Cannot dispose Link {this} (player=>server)"); + } } + + await _serverToPlayerTask; } - if (await WaitWithTimeout(_playerToServerTask)) + if (_playerToServerTask is not null) { - _logger.LogTrace("Timed out waiting Player {Player} disconnection from Server {Server}, closing manually", Player, Server); - await _ctsPlayerToServer.CancelAsync(); - if (await WaitWithTimeout(_playerToServerTask)) { - _logger.LogTrace("Timed out waiting Player {Player} disconnection from Server {Server} manually, closing forcefully", Player, Server); - await _ctsPlayerToServerForce.CancelAsync(); + logger.LogTrace("Timed out waiting Player {Player} disconnection from Server {Server}, closing manually", Player, Server); + await _ctsPlayerToServer.CancelAsync(); if (await WaitWithTimeout(_playerToServerTask)) - throw new Exception($"Cannot dispose Link {this} (server=>player)"); - } - } + { + logger.LogTrace("Timed out waiting Player {Player} disconnection from Server {Server} manually, closing forcefully", Player, Server); + await _ctsPlayerToServerForce.CancelAsync(); - await Task.WhenAll(_playerToServerTask, _serverToPlayerTask); - } + if (await WaitWithTimeout(_playerToServerTask)) + throw new Exception($"Cannot dispose Link {this} (server=>player)"); + } + } - public override string ToString() - { - return Player + " <=> " + Server; + await _playerToServerTask; + } } protected async Task ExecuteAsync(IMinecraftChannel sourceChannel, IMinecraftChannel destinationChannel, Direction direction, CancellationToken cancellationToken, CancellationToken forceCancellationToken) @@ -117,7 +114,7 @@ protected async Task ExecuteAsync(IMinecraftChannel sourceChannel, IMinecraftCha using var message = await sourceChannel.ReadMessageAsync(readingCancellationTokenSource.Token); - var cancelled = await _events.ThrowWithResultAsync(new MessageReceivedEvent + var cancelled = await events.ThrowWithResultAsync(new MessageReceivedEvent { From = (Side)direction, To = direction == Direction.Serverbound ? Side.Server : Side.Client, @@ -132,7 +129,7 @@ protected async Task ExecuteAsync(IMinecraftChannel sourceChannel, IMinecraftCha using var _ = await _lock.LockAsync(); await destinationChannel.WriteMessageAsync(message, forceCancellationToken); - await _events.ThrowAsync(new MessageSentEvent + await events.ThrowAsync(new MessageSentEvent { From = (Side)direction, To = direction == Direction.Serverbound ? Side.Server : Side.Client, @@ -152,7 +149,7 @@ await _events.ThrowAsync(new MessageSentEvent } catch (Exception exception) { - _logger.LogError(exception, "Unhandled {Direction} exception from {Player}", direction, Player); + logger.LogError(exception, "Unhandled {Direction} exception from {Player}", direction, Player); } finally { @@ -160,10 +157,15 @@ await _events.ThrowAsync(new MessageSentEvent await ServerChannel.FlushAsync(forceCancellationToken); if (sourceChannel == PlayerChannel) // throw event only once - _ = _events.ThrowAsync(new LinkStoppingEvent { Link = this }, forceCancellationToken).CatchExceptions(); + _ = events.ThrowAsync(new LinkStoppingEvent { Link = this }, forceCancellationToken).CatchExceptions(); } } + public override string ToString() + { + return Player + " <=> " + Server; + } + private static async Task WaitWithTimeout(Task task, int milliseconds = 5000) { var timeout = Task.Delay(milliseconds); diff --git a/src/Platform/Links/LinkService.cs b/src/Platform/Links/LinkService.cs index 635aaf0..7d28739 100644 --- a/src/Platform/Links/LinkService.cs +++ b/src/Platform/Links/LinkService.cs @@ -1,5 +1,6 @@ using Nito.AsyncEx; using Void.Proxy.API.Events; +using Void.Proxy.API.Events.Authentication; using Void.Proxy.API.Events.Links; using Void.Proxy.API.Events.Player; using Void.Proxy.API.Events.Services; @@ -70,13 +71,25 @@ private async ValueTask ConnectAsync(IPlayer player, IServer server, Cancellatio if (firstConnection) await _events.ThrowAsync(new PlayerConnectedEvent { Player = player }, cancellationToken); - var link = await _events.ThrowWithResultAsync(new CreateLinkEvent { Player = player, Server = server, PlayerChannel = playerChannel, ServerChannel = serverChannel }, cancellationToken) ?? new Link(player, server, playerChannel, serverChannel, _logger, _events); - await _events.ThrowAsync(new LinkStartingEvent { Link = link }, cancellationToken); + var link = await _events.ThrowWithResultAsync(new CreateLinkEvent + { + Player = player, + Server = server, + PlayerChannel = playerChannel, + ServerChannel = serverChannel + }, cancellationToken) ?? new Link(player, server, playerChannel, serverChannel, _logger, _events); - _events.RegisterListeners(link); _links.Add(link); - _logger.LogInformation("Started forwarding {Link} traffic", link); - await _events.ThrowAsync(new LinkStartedEvent { Link = link }, cancellationToken); + var side = await _events.ThrowWithResultAsync(new AuthenticationStartingEvent { Link = link }, cancellationToken); + + if (side is AuthenticationSide.Proxy && !await player.IsProtocolSupportedAsync(cancellationToken)) + { + _logger.LogWarning("Player {Player} protocol is not supported, forcing authentication to Server side", player); + side = AuthenticationSide.Server; + } + + await _events.ThrowAsync(new AuthenticationStartedEvent { Link = link, Side = side }, cancellationToken); + await link.StartAsync(cancellationToken); } } \ No newline at end of file diff --git a/src/Plugins/ModsSupport/Forge/ForgeMarker.cs b/src/Plugins/ModsSupport/Forge/ForgeMarker.cs index b727f21..2ed46fb 100644 --- a/src/Plugins/ModsSupport/Forge/ForgeMarker.cs +++ b/src/Plugins/ModsSupport/Forge/ForgeMarker.cs @@ -1,4 +1,4 @@ -namespace Void.Proxy.Plugins.ProtocolSupport.Java.v1_20_2_to_latest.Forge; +namespace Void.Proxy.Plugins.ModsSupport.Forge; // (HandshakePacket packet) // var addressParts = packet.ServerAddress.Split('\0', StringSplitOptions.RemoveEmptyEntries); @@ -9,7 +9,7 @@ // else if (addressParts.Length > 1) // Console.WriteLine($"Player {link.Player} had extra marker(s) {string.Join(", ", addressParts[1..])} in handshake, ignoring"); // -// link.SetProtocolVersion(ProtocolVersion.Search(packet.ProtocolVersion)); +// link.SetProtocolVersion(ProtocolVersion.Get(packet.ProtocolVersion)); // link.SwitchState(packet.NextState); // link.SaveHandshake(packet); diff --git a/src/Plugins/ProtocolSupport/Java/v1_13_to_1_20_1/Plugin.cs b/src/Plugins/ProtocolSupport/Java/v1_13_to_1_20_1/Plugin.cs index cad7b2b..067ede5 100644 --- a/src/Plugins/ProtocolSupport/Java/v1_13_to_1_20_1/Plugin.cs +++ b/src/Plugins/ProtocolSupport/Java/v1_13_to_1_20_1/Plugin.cs @@ -22,10 +22,10 @@ public void OnPluginLoad(PluginLoadEvent @event) Mappings.Fill(); - events.RegisterListeners(this); events.RegisterListeners(); + events.RegisterListeners(); + events.RegisterListeners(this); events.RegisterListeners(); events.RegisterListeners(); - events.RegisterListeners(); } } \ No newline at end of file diff --git a/src/Plugins/ProtocolSupport/Java/v1_20_2_to_latest/Plugin.cs b/src/Plugins/ProtocolSupport/Java/v1_20_2_to_latest/Plugin.cs index 207984b..6f16bda 100644 --- a/src/Plugins/ProtocolSupport/Java/v1_20_2_to_latest/Plugin.cs +++ b/src/Plugins/ProtocolSupport/Java/v1_20_2_to_latest/Plugin.cs @@ -22,10 +22,11 @@ public void OnPluginLoad(PluginLoadEvent @event) Mappings.Fill(); - events.RegisterListeners(this); events.RegisterListeners(); + events.RegisterListeners(); + events.RegisterListeners(this); events.RegisterListeners(); events.RegisterListeners(); - events.RegisterListeners(); + events.RegisterListeners(); } } \ No newline at end of file diff --git a/src/Plugins/ProtocolSupport/Java/v1_20_2_to_latest/Services/AuthenticationService.cs b/src/Plugins/ProtocolSupport/Java/v1_20_2_to_latest/Services/AuthenticationService.cs new file mode 100644 index 0000000..f9dca93 --- /dev/null +++ b/src/Plugins/ProtocolSupport/Java/v1_20_2_to_latest/Services/AuthenticationService.cs @@ -0,0 +1,66 @@ +using Microsoft.Extensions.Logging; +using Void.Proxy.API.Events; +using Void.Proxy.API.Events.Authentication; +using Void.Proxy.API.Events.Network; +using Void.Proxy.API.Events.Services; +using Void.Proxy.API.Links; +using Void.Proxy.API.Network; +using Void.Proxy.API.Network.IO.Messages; +using Void.Proxy.Common.Services; +using Void.Proxy.Plugins.ProtocolSupport.Java.v1_20_2_to_latest.Packets.Serverbound; + +namespace Void.Proxy.Plugins.ProtocolSupport.Java.v1_20_2_to_latest.Services; + +public class AuthenticationService(ILogger logger, IEventService events) : IPluginService +{ + [Subscribe] + public void OnAuthenticationStarting(AuthenticationStartingEvent @event) + { + if (Plugin.SupportedVersions.Contains(@event.Link.Player.ProtocolVersion)) + @event.Result = AuthenticationSide.Server; // TODO: change to Proxy side + } + + [Subscribe] + public async ValueTask OnAuthenticationStarted(AuthenticationStartedEvent @event, CancellationToken cancellationToken) + { + if (@event.Side is AuthenticationSide.Server) + return; + + var message = await @event.Link.PlayerChannel.ReadMessageAsync(cancellationToken); + + if (message is HandshakePacket handshake) + await SimulateMessageFlowAsync(Direction.Serverbound, @event.Link, handshake, cancellationToken); + + if (message is LoginStartPacket loginStart) + await SimulateMessageFlowAsync(Direction.Serverbound, @event.Link, loginStart, cancellationToken); + + logger.LogInformation("{MessageType}", message.ToString()); + + // this will get stuck after login start packet + await OnAuthenticationStarted(@event, cancellationToken); + } + + public async ValueTask SimulateMessageFlowAsync(Direction direction, ILink link, IMinecraftMessage message, CancellationToken cancellationToken) + { + var cancelled = await events.ThrowWithResultAsync(new MessageReceivedEvent + { + Direction = Direction.Serverbound, + From = Side.Client, + To = Side.Server, + Link = link, + Message = message + }, cancellationToken); + + if (cancelled) + throw new NotSupportedException("Cancelling incoming packets at authentication on Proxy side is not supported yet"); + + await events.ThrowAsync(new MessageSentEvent + { + Direction = Direction.Serverbound, + From = Side.Client, + To = Side.Server, + Link = link, + Message = message + }, cancellationToken); + } +} \ No newline at end of file diff --git a/src/Plugins/ProtocolSupport/Java/v1_7_2_to_1_12_2/Plugin.cs b/src/Plugins/ProtocolSupport/Java/v1_7_2_to_1_12_2/Plugin.cs index 80e5b2a..ee2e5d0 100644 --- a/src/Plugins/ProtocolSupport/Java/v1_7_2_to_1_12_2/Plugin.cs +++ b/src/Plugins/ProtocolSupport/Java/v1_7_2_to_1_12_2/Plugin.cs @@ -22,10 +22,10 @@ public void OnPluginLoad(PluginLoadEvent @event) Mappings.Fill(); - events.RegisterListeners(this); events.RegisterListeners(); + events.RegisterListeners(); + events.RegisterListeners(this); events.RegisterListeners(); events.RegisterListeners(); - events.RegisterListeners(); } } \ No newline at end of file