feat(velocity): Improved performance and organization of listener registrations

This commit is contained in:
Adrian 2023-05-24 17:56:42 -05:00
parent d597b1e33e
commit fed2b4a66b
No known key found for this signature in database
GPG Key ID: FB8EF84DCE1BE452
17 changed files with 673 additions and 422 deletions

View File

@ -32,7 +32,7 @@ dependencies {
tasks { tasks {
shadowJar { shadowJar {
archiveFileName.set("AuthMeVelocity-Paper-${project.version}.jar") archiveBaseName.set("AuthMeVelocity-Paper")
archiveClassifier.set("") archiveClassifier.set("")
relocate("net.byteflux.libby", "io.github._4drian3d.authmevelocity.libs.libby") relocate("net.byteflux.libby", "io.github._4drian3d.authmevelocity.libs.libby")

View File

@ -1,6 +1,7 @@
name: AuthMeVelocity name: AuthMeVelocity
version: '${version}' version: '${version}'
main: io.github._4drian3d.authmevelocity.paper.AuthMeVelocityPlugin main: io.github._4drian3d.authmevelocity.paper.AuthMeVelocityPlugin
bootstrapper: io.github._4drian3d.authmevelocity.paper.AuthMeVelocityBootstrap
description: AuthMeReloaded Support for Velocity description: AuthMeReloaded Support for Velocity
authors: authors:
- xQuickGlare - xQuickGlare

View File

@ -39,7 +39,7 @@ tasks {
shadowJar { shadowJar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE duplicatesStrategy = DuplicatesStrategy.EXCLUDE
archiveFileName.set("AuthMeVelocity-Proxy-${project.version}.jar") archiveBaseName.set("AuthMeVelocity-Velocity")
archiveClassifier.set("") archiveClassifier.set("")
relocate("org.bstats", "io.github._4drian3d.authmevelocity.libs.bstats") relocate("org.bstats", "io.github._4drian3d.authmevelocity.libs.bstats")

View File

@ -20,7 +20,6 @@ package io.github._4drian3d.authmevelocity.velocity;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Injector; import com.google.inject.Injector;
import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.event.EventManager;
import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.plugin.Dependency; import com.velocitypowered.api.plugin.Dependency;
@ -40,10 +39,16 @@ import io.github._4drian3d.authmevelocity.common.LibsManager;
import io.github._4drian3d.authmevelocity.common.configuration.ConfigurationContainer; import io.github._4drian3d.authmevelocity.common.configuration.ConfigurationContainer;
import io.github._4drian3d.authmevelocity.common.configuration.ProxyConfiguration; import io.github._4drian3d.authmevelocity.common.configuration.ProxyConfiguration;
import io.github._4drian3d.authmevelocity.velocity.commands.AuthMeCommand; import io.github._4drian3d.authmevelocity.velocity.commands.AuthMeCommand;
import io.github._4drian3d.authmevelocity.velocity.listener.ConnectListener; import io.github._4drian3d.authmevelocity.velocity.listener.Listener;
import io.github._4drian3d.authmevelocity.velocity.listener.FastLoginListener; import io.github._4drian3d.authmevelocity.velocity.listener.compat.FastLoginListener;
import io.github._4drian3d.authmevelocity.velocity.listener.PluginMessageListener; import io.github._4drian3d.authmevelocity.velocity.listener.connection.DisconnectListener;
import io.github._4drian3d.authmevelocity.velocity.listener.ProxyListener; import io.github._4drian3d.authmevelocity.velocity.listener.connection.InitialServerListener;
import io.github._4drian3d.authmevelocity.velocity.listener.connection.PostConnectListener;
import io.github._4drian3d.authmevelocity.velocity.listener.connection.PreConnectListener;
import io.github._4drian3d.authmevelocity.velocity.listener.data.PluginMessageListener;
import io.github._4drian3d.authmevelocity.velocity.listener.input.ChatListener;
import io.github._4drian3d.authmevelocity.velocity.listener.input.CommandListener;
import io.github._4drian3d.authmevelocity.velocity.listener.input.TabCompleteListener;
import net.byteflux.libby.VelocityLibraryManager; import net.byteflux.libby.VelocityLibraryManager;
import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bstats.charts.SimplePie; import org.bstats.charts.SimplePie;
@ -84,8 +89,6 @@ public final class AuthMeVelocityPlugin implements AuthMeVelocityAPI {
@Inject @Inject
private ProxyServer proxy; private ProxyServer proxy;
@Inject @Inject
private EventManager eventManager;
@Inject
private PluginManager pluginManager; private PluginManager pluginManager;
@Inject @Inject
private Logger logger; private Logger logger;
@ -123,17 +126,22 @@ public final class AuthMeVelocityPlugin implements AuthMeVelocityAPI {
proxy.getChannelRegistrar().register(MODERN_CHANNEL, LEGACY_CHANNEL); proxy.getChannelRegistrar().register(MODERN_CHANNEL, LEGACY_CHANNEL);
Stream.of( Stream.of(
ProxyListener.class, PluginMessageListener.class,
ConnectListener.class, DisconnectListener.class,
PluginMessageListener.class InitialServerListener.class,
PostConnectListener.class,
PreConnectListener.class,
ChatListener.class,
CommandListener.class,
TabCompleteListener.class
).map(injector::getInstance) ).map(injector::getInstance)
.forEach(listener -> eventManager.register(this, listener)); .forEach(Listener::register);
final boolean fastlogin = pluginManager.isLoaded("fastlogin"); final boolean fastlogin = pluginManager.isLoaded("fastlogin");
metrics.addCustomChart(new SimplePie("fastlogin_compatibility", () -> Boolean.toString(fastlogin))); metrics.addCustomChart(new SimplePie("fastlogin_compatibility", () -> Boolean.toString(fastlogin)));
if (fastlogin) { if (fastlogin) {
logDebug("Register FastLogin compatibility"); logDebug("Register FastLogin compatibility");
eventManager.register(this, injector.getInstance(FastLoginListener.class)); injector.getInstance(FastLoginListener.class).register();
} }
final boolean miniplaceholders = pluginManager.isLoaded("miniplaceholders"); final boolean miniplaceholders = pluginManager.isLoaded("miniplaceholders");

View File

@ -1,137 +0,0 @@
/*
* Copyright (C) 2023 AuthMeVelocity Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package io.github._4drian3d.authmevelocity.velocity.listener;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import com.google.inject.Inject;
import com.velocitypowered.api.event.Continuation;
import com.velocitypowered.api.event.PostOrder;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.player.PlayerChooseInitialServerEvent;
import com.velocitypowered.api.event.player.ServerPostConnectEvent;
import com.velocitypowered.api.event.player.ServerPreConnectEvent;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.ServerConnection;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import io.github._4drian3d.authmevelocity.common.configuration.ProxyConfiguration;
import io.github._4drian3d.authmevelocity.velocity.AuthMeVelocityPlugin;
import io.github._4drian3d.authmevelocity.velocity.utils.AuthMeUtils;
import io.github._4drian3d.authmevelocity.velocity.utils.Pair;
import org.slf4j.Logger;
import java.util.Optional;
public final class ConnectListener {
@Inject
private ProxyServer proxy;
@Inject
private Logger logger;
@Inject
private AuthMeVelocityPlugin plugin;
@Subscribe(order = PostOrder.LATE)
public void onInitialServer(
final PlayerChooseInitialServerEvent event,
Continuation continuation
) {
if (!plugin.config().get().ensureAuthServer().ensureFirstServerIsAuthServer()) {
continuation.resume();
plugin.logDebug("PlayerChooseInitialServerEvent | Not enabled");
return;
}
final Optional<RegisteredServer> optionalSV = event.getInitialServer();
if (optionalSV.isPresent() && plugin.isAuthServer(optionalSV.get())) {
continuation.resume();
plugin.logDebug("PlayerChooseInitialServerEvent | Player is in auth server");
return;
}
final ProxyConfiguration config = plugin.config().get();
final Pair<RegisteredServer> server = AuthMeUtils.serverToSend(
config.ensureAuthServer().sendMode(), proxy, config.authServers(), config.advanced().randomAttempts());
// Velocity takes over in case the initial server is not present
event.setInitialServer(server.object());
continuation.resume();
if (server.isEmpty()) {
plugin.logDebug("PlayerChooseInitialServerEvent | Null server");
logger.error("Cannot send the player {} to an auth server", event.getPlayer().getUsername());
}
}
@Subscribe
public void onServerPreConnect(
final ServerPreConnectEvent event,
final Continuation continuation
) {
if (plugin.isLogged(event.getPlayer())) {
plugin.logDebug("ServerPreConnectEvent | Player already logged");
continuation.resume();
return;
}
final RegisteredServer server = event.getResult().getServer().orElse(null);
if (server == null) {
plugin.logDebug("ServerPreConnectEvent | Null Server");
continuation.resume();
return;
}
// this should be present, "event.getResult().isAllowed()" is the "isPresent" check
if (!plugin.isAuthServer(server)) {
plugin.logDebug("ServerPreConnectEvent | Server "+server.getServerInfo().getName()+" is not an auth server");
event.setResult(ServerPreConnectEvent.ServerResult.denied());
} else {
plugin.logDebug("ServerPreConnectEvent | Server "+server.getServerInfo().getName()+" is an auth server");
}
continuation.resume();
}
@SuppressWarnings("UnstableApiUsage")
@Subscribe
public void onServerPostConnect(final ServerPostConnectEvent event) {
final Player player = event.getPlayer();
final boolean isLogged = plugin.isLogged(player);
plugin.logDebug("ServerPostConnectEvent | Player "+player.getUsername()+" is logged: " + isLogged);
final RegisteredServer server = player.getCurrentServer().map(ServerConnection::getServer).orElse(null);
if (server == null) {
plugin.logDebug("ServerPostConnectEvent | Player "+player.getUsername()+" is not in a server");
return;
}
final boolean isInAuthServer = plugin.isInAuthServer(player);
plugin.logDebug("ServerPostConnectEvent | Player "+player.getUsername()+" is in AuthServer: " + isInAuthServer);
if (!(isLogged && isInAuthServer)) {
return;
}
plugin.logDebug("ServerPostConnectEvent | Already logged player and connected to an Auth server");
final ByteArrayDataOutput buf = ByteStreams.newDataOutput();
buf.writeUTF("LOGIN");
final byte[] byteArray = buf.toByteArray();
plugin.logDebug("ServerPostConnectEvent | Sending LOGIN data");
if (server.sendPluginMessage(AuthMeVelocityPlugin.MODERN_CHANNEL, byteArray)) {
plugin.logDebug("ServerPostConnectEvent | Correctly send data");
} else {
plugin.logDebug("ServerPostConnectEvent | Failed to send data");
}
}
}

View File

@ -0,0 +1,24 @@
/*
* Copyright (C) 2023 AuthMeVelocity Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package io.github._4drian3d.authmevelocity.velocity.listener;
import com.velocitypowered.api.event.AwaitingEventExecutor;
public interface Listener<E> extends AwaitingEventExecutor<E> {
void register();
}

View File

@ -1,148 +0,0 @@
/*
* Copyright (C) 2023 AuthMeVelocity Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package io.github._4drian3d.authmevelocity.velocity.listener;
import com.google.common.io.ByteArrayDataInput;
import com.google.inject.Inject;
import com.velocitypowered.api.event.Continuation;
import com.velocitypowered.api.event.EventManager;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.connection.PluginMessageEvent;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.ServerConnection;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import io.github._4drian3d.authmevelocity.api.velocity.event.*;
import io.github._4drian3d.authmevelocity.common.MessageType;
import io.github._4drian3d.authmevelocity.common.configuration.ProxyConfiguration;
import io.github._4drian3d.authmevelocity.velocity.AuthMeVelocityPlugin;
import io.github._4drian3d.authmevelocity.velocity.utils.AuthMeUtils;
import io.github._4drian3d.authmevelocity.velocity.utils.Pair;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import java.util.Locale;
public class PluginMessageListener {
@Inject
private ProxyServer proxy;
@Inject
private EventManager eventManager;
@Inject
private Logger logger;
@Inject
private AuthMeVelocityPlugin plugin;
@Subscribe
public void onPluginMessage(final PluginMessageEvent event, Continuation continuation) {
final boolean cancelled = !event.getResult().isAllowed()
|| !(event.getSource() instanceof ServerConnection)
|| !(event.getIdentifier().equals(AuthMeVelocityPlugin.MODERN_CHANNEL)
|| event.getIdentifier().equals(AuthMeVelocityPlugin.LEGACY_CHANNEL));
if (cancelled) {
continuation.resume();
plugin.logDebug("PluginMessageEvent | Not allowed");
return;
}
final ServerConnection connection = (ServerConnection) event.getSource();
event.setResult(PluginMessageEvent.ForwardResult.handled());
final ByteArrayDataInput input = event.dataAsDataStream();
final String message = input.readUTF();
final MessageType type = MessageType.valueOf(
message.toUpperCase(Locale.ROOT));
final String name = input.readUTF();
final @Nullable Player player = proxy.getPlayer(name).orElse(null);
switch (type) {
case LOGIN -> {
plugin.logDebug("PluginMessageEvent | Login type");
if (player != null && plugin.addPlayer(player)) {
eventManager.fireAndForget(new ProxyLoginEvent(player));
if (plugin.config().get().sendOnLogin().sendToServerOnLogin()) {
this.createServerConnectionRequest(player, connection);
}
plugin.logDebug("PluginMessageEvent | Player not null");
}
}
case LOGOUT -> {
plugin.logDebug("PluginMessageEvent | Logout type");
if (player != null && plugin.removePlayer(player)){
eventManager.fireAndForget(new ProxyLogoutEvent(player));
plugin.logDebug("PluginMessageEvent | Player not null");
}
}
case REGISTER -> {
plugin.logDebug("PluginMessageEvent | Register");
if (player != null) {
eventManager.fireAndForget(new ProxyRegisterEvent(player));
plugin.logDebug("PluginMessageEvent | Player not null");
}
}
case UNREGISTER -> {
plugin.logDebug("PluginMessageEvent | Unregister type");
if (player != null) {
plugin.logDebug("PluginMessageEvent | Player not null");
eventManager.fireAndForget(new ProxyUnregisterEvent(player));
}
}
case FORCE_UNREGISTER -> {
eventManager.fireAndForget(new ProxyForcedUnregisterEvent(player));
plugin.logDebug("PluginMessageEvent | Forced Unregister type");
}
}
continuation.resume();
}
private void createServerConnectionRequest(Player player, ServerConnection connection){
final RegisteredServer loginServer = player.getCurrentServer().orElse(connection).getServer();
final ProxyConfiguration config = plugin.config().get();
final Pair<RegisteredServer> toSend = AuthMeUtils.serverToSend(
config.sendOnLogin().sendMode(), proxy, config.sendOnLogin().teleportServers(), config.advanced().randomAttempts());
if (toSend.isEmpty()) {
if (toSend.string() != null) {
logger.warn("The server {} does not exist", toSend.string());
} else {
logger.warn("There is not valid server to send");
}
return;
}
eventManager.fire(new PreSendOnLoginEvent(player, loginServer, toSend.object()))
.thenAccept(event -> {
if (!event.getResult().isAllowed()) {
return;
}
player.createConnectionRequest(event.getResult().getServer())
.connect()
.thenAcceptAsync(result -> {
if (!result.isSuccessful()) {
logger.info("Unable to connect the player {} to the server {}",
player.getUsername(),
result.getAttemptedConnection().getServerInfo().getName());
}
});
});
}
}

View File

@ -1,116 +0,0 @@
/*
* Copyright (C) 2023 AuthMeVelocity Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package io.github._4drian3d.authmevelocity.velocity.listener;
import com.google.inject.Inject;
import com.velocitypowered.api.event.Continuation;
import com.velocitypowered.api.event.EventTask;
import com.velocitypowered.api.event.PostOrder;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.command.CommandExecuteEvent;
import com.velocitypowered.api.event.connection.DisconnectEvent;
import com.velocitypowered.api.event.player.PlayerChatEvent;
import com.velocitypowered.api.event.player.TabCompleteEvent;
import com.velocitypowered.api.proxy.Player;
import io.github._4drian3d.authmevelocity.velocity.AuthMeVelocityPlugin;
import io.github._4drian3d.authmevelocity.velocity.utils.AuthMeUtils;
import net.kyori.adventure.text.minimessage.MiniMessage;
public final class ProxyListener {
@Inject
private AuthMeVelocityPlugin plugin;
@Subscribe
public EventTask onDisconnect(final DisconnectEvent event) {
if (event.getLoginStatus() == DisconnectEvent.LoginStatus.CONFLICTING_LOGIN) {
return null;
}
return EventTask.async(() -> plugin.removePlayer(event.getPlayer()));
}
@Subscribe(order = PostOrder.FIRST)
public void onCommandExecute(final CommandExecuteEvent event, Continuation continuation) {
if (!(event.getCommandSource() instanceof final Player player)){
plugin.logDebug("CommandExecuteEvent | CommandSource is not a player");
continuation.resume();
return;
}
if (plugin.isLogged(player)) {
plugin.logDebug("CommandExecuteEvent | Player is already logged");
continuation.resume();
return;
}
if (plugin.isInAuthServer(player)) {
plugin.logDebug("CommandExecuteEvent | Player is in Auth Server");
String command = AuthMeUtils.getFirstArgument(event.getCommand());
if (!plugin.config().get().commands().allowedCommands().contains(command)) {
plugin.logDebug("CommandExecuteEvent | Player executed an blocked command");
sendBlockedMessage(player);
event.setResult(CommandExecuteEvent.CommandResult.denied());
}
} else {
plugin.logDebug("CommandExecuteEven | Player is not in auth server");
sendBlockedMessage(player);
event.setResult(CommandExecuteEvent.CommandResult.denied());
}
continuation.resume();
}
@Subscribe(order = PostOrder.FIRST)
public void onPlayerChat(final PlayerChatEvent event, Continuation continuation) {
if (plugin.isLogged(event.getPlayer())) {
plugin.logDebug("PlayerChatEvent | Player is already logged");
continuation.resume();
return;
}
plugin.logDebug("PlayerChatEvent | Player is not logged");
event.setResult(PlayerChatEvent.ChatResult.denied());
continuation.resume();
}
@Subscribe(order = PostOrder.FIRST)
public void onTabComplete(TabCompleteEvent event){
if (plugin.isLogged(event.getPlayer())) {
plugin.logDebug("TabCompleteEvent | Player is already logged");
return;
}
final String command = event.getPartialMessage();
for (final String allowed : plugin.config().get().commands().allowedCommands()) {
if (allowed.startsWith(command)) {
return;
}
}
plugin.logDebug("TabCompleteEvent | Not allowed tab-completion");
event.getSuggestions().clear();
}
void sendBlockedMessage(Player player){
String blockedMessage = plugin.config().get().commands().blockedCommandMessage();
if (!blockedMessage.isBlank()){
player.sendMessage(MiniMessage.miniMessage().deserialize(blockedMessage));
}
}
}

View File

@ -15,23 +15,31 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package io.github._4drian3d.authmevelocity.velocity.listener; package io.github._4drian3d.authmevelocity.velocity.listener.compat;
import com.github.games647.fastlogin.velocity.event.VelocityFastLoginAutoLoginEvent; import com.github.games647.fastlogin.velocity.event.VelocityFastLoginAutoLoginEvent;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.EventTask;
import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.ProxyServer;
import io.github._4drian3d.authmevelocity.velocity.AuthMeVelocityPlugin; import io.github._4drian3d.authmevelocity.velocity.AuthMeVelocityPlugin;
import io.github._4drian3d.authmevelocity.velocity.listener.Listener;
public class FastLoginListener { public final class FastLoginListener implements Listener<VelocityFastLoginAutoLoginEvent> {
@Inject @Inject
private ProxyServer proxy; private ProxyServer proxy;
@Inject @Inject
private AuthMeVelocityPlugin plugin; private AuthMeVelocityPlugin plugin;
@Subscribe @Override
public void onAutoLogin(VelocityFastLoginAutoLoginEvent event){ public void register() {
plugin.logDebug("VelocityFastLoginAutoLoginEvent | Attempt to auto register player"); proxy.getEventManager().register(plugin, VelocityFastLoginAutoLoginEvent.class, this);
proxy.getPlayer(event.getProfile().getName()).ifPresent(plugin::addPlayer); }
@Override
public EventTask executeAsync(final VelocityFastLoginAutoLoginEvent event) {
return EventTask.async(() -> {
plugin.logDebug("VelocityFastLoginAutoLoginEvent | Attempt to auto register player");
proxy.getPlayer(event.getProfile().getName()).ifPresent(plugin::addPlayer);
});
} }
} }

View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2023 AuthMeVelocity Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package io.github._4drian3d.authmevelocity.velocity.listener.connection;
import com.google.inject.Inject;
import com.velocitypowered.api.event.EventManager;
import com.velocitypowered.api.event.EventTask;
import com.velocitypowered.api.event.connection.DisconnectEvent;
import io.github._4drian3d.authmevelocity.velocity.AuthMeVelocityPlugin;
import io.github._4drian3d.authmevelocity.velocity.listener.Listener;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class DisconnectListener implements Listener<DisconnectEvent> {
@Inject
private AuthMeVelocityPlugin plugin;
@Inject
private EventManager eventManager;
@Override
public void register() {
eventManager.register(plugin, DisconnectEvent.class, this);
}
@Override
public @Nullable EventTask executeAsync(final DisconnectEvent event) {
if (event.getLoginStatus() == DisconnectEvent.LoginStatus.CONFLICTING_LOGIN) {
return null;
}
return EventTask.async(() -> plugin.removePlayer(event.getPlayer()));
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright (C) 2023 AuthMeVelocity Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package io.github._4drian3d.authmevelocity.velocity.listener.connection;
import com.google.inject.Inject;
import com.velocitypowered.api.event.EventManager;
import com.velocitypowered.api.event.EventTask;
import com.velocitypowered.api.event.PostOrder;
import com.velocitypowered.api.event.player.PlayerChooseInitialServerEvent;
import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import io.github._4drian3d.authmevelocity.common.configuration.ProxyConfiguration;
import io.github._4drian3d.authmevelocity.velocity.AuthMeVelocityPlugin;
import io.github._4drian3d.authmevelocity.velocity.listener.Listener;
import io.github._4drian3d.authmevelocity.velocity.utils.AuthMeUtils;
import io.github._4drian3d.authmevelocity.velocity.utils.Pair;
import org.slf4j.Logger;
import java.util.Optional;
public final class InitialServerListener implements Listener<PlayerChooseInitialServerEvent> {
@Inject
private AuthMeVelocityPlugin plugin;
@Inject
private EventManager eventManager;
@Inject
private ProxyServer proxy;
@Inject
private Logger logger;
@Override
public void register() {
eventManager.register(plugin, PlayerChooseInitialServerEvent.class, PostOrder.LATE, this);
}
@Override
public EventTask executeAsync(final PlayerChooseInitialServerEvent event) {
return EventTask.withContinuation(continuation -> {
final ProxyConfiguration config = plugin.config().get();
if (!config.ensureAuthServer().ensureFirstServerIsAuthServer()) {
continuation.resume();
plugin.logDebug("PlayerChooseInitialServerEvent | Not enabled");
return;
}
final Optional<RegisteredServer> optionalSV = event.getInitialServer();
if (optionalSV.isPresent() && plugin.isAuthServer(optionalSV.get())) {
continuation.resume();
plugin.logDebug("PlayerChooseInitialServerEvent | Player is in auth server");
return;
}
final Pair<RegisteredServer> server = AuthMeUtils.serverToSend(
config.ensureAuthServer().sendMode(), proxy, config.authServers(), config.advanced().randomAttempts());
// Velocity takes over in case the initial server is not present
event.setInitialServer(server.object());
continuation.resume();
if (server.isEmpty()) {
plugin.logDebug("PlayerChooseInitialServerEvent | Null server");
logger.error("Cannot send the player {} to an auth server", event.getPlayer().getUsername());
}
});
}
}

View File

@ -0,0 +1,75 @@
/*
* Copyright (C) 2023 AuthMeVelocity Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package io.github._4drian3d.authmevelocity.velocity.listener.connection;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import com.google.inject.Inject;
import com.velocitypowered.api.event.EventManager;
import com.velocitypowered.api.event.EventTask;
import com.velocitypowered.api.event.player.ServerPostConnectEvent;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ServerConnection;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import io.github._4drian3d.authmevelocity.velocity.AuthMeVelocityPlugin;
import io.github._4drian3d.authmevelocity.velocity.listener.Listener;
public final class PostConnectListener implements Listener<ServerPostConnectEvent> {
@Inject
private AuthMeVelocityPlugin plugin;
@Inject
private EventManager eventManager;
@Override
public void register() {
eventManager.register(plugin, ServerPostConnectEvent.class, this);
}
@Override
public EventTask executeAsync(final ServerPostConnectEvent event) {
return EventTask.async(() -> {
final Player player = event.getPlayer();
final boolean isLogged = plugin.isLogged(player);
plugin.logDebug("ServerPostConnectEvent | Player "+player.getUsername()+" is logged: " + isLogged);
final RegisteredServer server = player.getCurrentServer().map(ServerConnection::getServer).orElse(null);
if (server == null) {
plugin.logDebug("ServerPostConnectEvent | Player "+player.getUsername()+" is not in a server");
return;
}
final boolean isInAuthServer = plugin.isInAuthServer(player);
plugin.logDebug("ServerPostConnectEvent | Player "+player.getUsername()+" is in AuthServer: " + isInAuthServer);
if (!(isLogged && isInAuthServer)) {
return;
}
plugin.logDebug("ServerPostConnectEvent | Already logged player and connected to an Auth server");
final ByteArrayDataOutput buf = ByteStreams.newDataOutput();
buf.writeUTF("LOGIN");
final byte[] byteArray = buf.toByteArray();
plugin.logDebug("ServerPostConnectEvent | Sending LOGIN data");
if (server.sendPluginMessage(AuthMeVelocityPlugin.MODERN_CHANNEL, byteArray)) {
plugin.logDebug("ServerPostConnectEvent | Correctly send data");
} else {
plugin.logDebug("ServerPostConnectEvent | Failed to send data");
}
});
}
}

View File

@ -0,0 +1,64 @@
/*
* Copyright (C) 2023 AuthMeVelocity Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package io.github._4drian3d.authmevelocity.velocity.listener.connection;
import com.google.inject.Inject;
import com.velocitypowered.api.event.EventManager;
import com.velocitypowered.api.event.EventTask;
import com.velocitypowered.api.event.player.ServerPreConnectEvent;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import io.github._4drian3d.authmevelocity.velocity.AuthMeVelocityPlugin;
import io.github._4drian3d.authmevelocity.velocity.listener.Listener;
public final class PreConnectListener implements Listener<ServerPreConnectEvent> {
@Inject
private AuthMeVelocityPlugin plugin;
@Inject
private EventManager eventManager;
@Override
public void register() {
eventManager.register(plugin, ServerPreConnectEvent.class, this);
}
@Override
public EventTask executeAsync(final ServerPreConnectEvent event) {
return EventTask.withContinuation(continuation -> {
if (plugin.isLogged(event.getPlayer())) {
plugin.logDebug("ServerPreConnectEvent | Player already logged");
continuation.resume();
return;
}
final RegisteredServer server = event.getResult().getServer().orElse(null);
if (server == null) {
plugin.logDebug("ServerPreConnectEvent | Null Server");
continuation.resume();
return;
}
// this should be present, "event.getResult().isAllowed()" is the "isPresent" check
if (!plugin.isAuthServer(server)) {
plugin.logDebug("ServerPreConnectEvent | Server "+server.getServerInfo().getName()+" is not an auth server");
event.setResult(ServerPreConnectEvent.ServerResult.denied());
} else {
plugin.logDebug("ServerPreConnectEvent | Server "+server.getServerInfo().getName()+" is an auth server");
}
continuation.resume();
});
}
}

View File

@ -0,0 +1,153 @@
/*
* Copyright (C) 2023 AuthMeVelocity Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package io.github._4drian3d.authmevelocity.velocity.listener.data;
import com.google.common.io.ByteArrayDataInput;
import com.google.inject.Inject;
import com.velocitypowered.api.event.EventManager;
import com.velocitypowered.api.event.EventTask;
import com.velocitypowered.api.event.connection.PluginMessageEvent;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.ServerConnection;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import io.github._4drian3d.authmevelocity.api.velocity.event.*;
import io.github._4drian3d.authmevelocity.common.MessageType;
import io.github._4drian3d.authmevelocity.common.configuration.ProxyConfiguration;
import io.github._4drian3d.authmevelocity.velocity.AuthMeVelocityPlugin;
import io.github._4drian3d.authmevelocity.velocity.listener.Listener;
import io.github._4drian3d.authmevelocity.velocity.utils.AuthMeUtils;
import io.github._4drian3d.authmevelocity.velocity.utils.Pair;
import net.kyori.adventure.util.Index;
import org.slf4j.Logger;
import java.util.Locale;
public final class PluginMessageListener implements Listener<PluginMessageEvent> {
private static final Index<String, MessageType> TYPES = Index.create(MessageType.class, Enum::toString);
@Inject
private ProxyServer proxy;
@Inject
private EventManager eventManager;
@Inject
private Logger logger;
@Inject
private AuthMeVelocityPlugin plugin;
@Override
public void register() {
eventManager.register(plugin, PluginMessageEvent.class, this);
}
@Override
public EventTask executeAsync(final PluginMessageEvent event) {
return EventTask.async(() -> {
final boolean cancelled = !event.getResult().isAllowed()
|| !(event.getSource() instanceof ServerConnection)
|| !(event.getIdentifier().equals(AuthMeVelocityPlugin.MODERN_CHANNEL)
|| event.getIdentifier().equals(AuthMeVelocityPlugin.LEGACY_CHANNEL));
if (cancelled) {
plugin.logDebug("PluginMessageEvent | Not allowed");
return;
}
final ServerConnection connection = (ServerConnection) event.getSource();
event.setResult(PluginMessageEvent.ForwardResult.handled());
final ByteArrayDataInput input = event.dataAsDataStream();
final String message = input.readUTF();
final MessageType type = TYPES.valueOrThrow(message.toUpperCase(Locale.ROOT));
final String name = input.readUTF();
final Player player = proxy.getPlayer(name).orElse(null);
switch (type) {
case LOGIN -> {
plugin.logDebug("PluginMessageEvent | Login type");
if (player != null && plugin.addPlayer(player)) {
eventManager.fireAndForget(new ProxyLoginEvent(player));
if (plugin.config().get().sendOnLogin().sendToServerOnLogin()) {
this.createServerConnectionRequest(player, connection);
}
plugin.logDebug("PluginMessageEvent | Player not null");
}
}
case LOGOUT -> {
plugin.logDebug("PluginMessageEvent | Logout type");
if (player != null && plugin.removePlayer(player)){
eventManager.fireAndForget(new ProxyLogoutEvent(player));
plugin.logDebug("PluginMessageEvent | Player not null");
}
}
case REGISTER -> {
plugin.logDebug("PluginMessageEvent | Register");
if (player != null) {
eventManager.fireAndForget(new ProxyRegisterEvent(player));
plugin.logDebug("PluginMessageEvent | Player not null");
}
}
case UNREGISTER -> {
plugin.logDebug("PluginMessageEvent | Unregister type");
if (player != null) {
plugin.logDebug("PluginMessageEvent | Player not null");
eventManager.fireAndForget(new ProxyUnregisterEvent(player));
}
}
case FORCE_UNREGISTER -> {
eventManager.fireAndForget(new ProxyForcedUnregisterEvent(player));
plugin.logDebug("PluginMessageEvent | Forced Unregister type");
}
}
});
}
private void createServerConnectionRequest(final Player player, final ServerConnection connection){
final RegisteredServer loginServer = player.getCurrentServer().orElse(connection).getServer();
final ProxyConfiguration config = plugin.config().get();
final Pair<RegisteredServer> toSend = AuthMeUtils.serverToSend(
config.sendOnLogin().sendMode(), proxy, config.sendOnLogin().teleportServers(), config.advanced().randomAttempts());
if (toSend.isEmpty()) {
if (toSend.string() != null) {
logger.warn("The server {} does not exist", toSend.string());
} else {
logger.warn("There is not valid server to send");
}
return;
}
eventManager.fire(new PreSendOnLoginEvent(player, loginServer, toSend.object()))
.thenAccept(event -> {
if (!event.getResult().isAllowed()) {
return;
}
player.createConnectionRequest(event.getResult().getServer())
.connect()
.thenAcceptAsync(result -> {
if (!result.isSuccessful()) {
logger.info("Unable to connect the player {} to the server {}",
player.getUsername(),
result.getAttemptedConnection().getServerInfo().getName());
}
});
});
}
}

View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2023 AuthMeVelocity Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package io.github._4drian3d.authmevelocity.velocity.listener.input;
import com.google.inject.Inject;
import com.velocitypowered.api.event.EventManager;
import com.velocitypowered.api.event.EventTask;
import com.velocitypowered.api.event.PostOrder;
import com.velocitypowered.api.event.player.PlayerChatEvent;
import io.github._4drian3d.authmevelocity.velocity.AuthMeVelocityPlugin;
import io.github._4drian3d.authmevelocity.velocity.listener.Listener;
public final class ChatListener implements Listener<PlayerChatEvent> {
@Inject
private AuthMeVelocityPlugin plugin;
@Inject
private EventManager eventManager;
@Override
public void register() {
eventManager.register(plugin, PlayerChatEvent.class, PostOrder.FIRST, this);
}
@Override
public EventTask executeAsync(final PlayerChatEvent event) {
return EventTask.withContinuation(continuation -> {
if (plugin.isLogged(event.getPlayer())) {
plugin.logDebug("PlayerChatEvent | Player is already logged");
continuation.resume();
return;
}
plugin.logDebug("PlayerChatEvent | Player is not logged");
event.setResult(PlayerChatEvent.ChatResult.denied());
continuation.resume();
});
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright (C) 2023 AuthMeVelocity Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package io.github._4drian3d.authmevelocity.velocity.listener.input;
import com.google.inject.Inject;
import com.velocitypowered.api.event.EventManager;
import com.velocitypowered.api.event.EventTask;
import com.velocitypowered.api.event.PostOrder;
import com.velocitypowered.api.event.command.CommandExecuteEvent;
import com.velocitypowered.api.proxy.Player;
import io.github._4drian3d.authmevelocity.velocity.AuthMeVelocityPlugin;
import io.github._4drian3d.authmevelocity.velocity.listener.Listener;
import io.github._4drian3d.authmevelocity.velocity.utils.AuthMeUtils;
import net.kyori.adventure.text.minimessage.MiniMessage;
public final class CommandListener implements Listener<CommandExecuteEvent> {
@Inject
private EventManager eventManager;
@Inject
private AuthMeVelocityPlugin plugin;
@Override
public void register() {
eventManager.register(plugin, CommandExecuteEvent.class, PostOrder.FIRST, this);
}
@Override
public EventTask executeAsync(final CommandExecuteEvent event) {
return EventTask.withContinuation(continuation -> {
if (!(event.getCommandSource() instanceof final Player player)) {
plugin.logDebug("CommandExecuteEvent | CommandSource is not a player");
continuation.resume();
return;
}
if (plugin.isLogged(player)) {
plugin.logDebug("CommandExecuteEvent | Player is already logged");
continuation.resume();
return;
}
if (plugin.isInAuthServer(player)) {
plugin.logDebug("CommandExecuteEvent | Player is in Auth Server");
final String command = AuthMeUtils.getFirstArgument(event.getCommand());
if (!plugin.config().get().commands().allowedCommands().contains(command)) {
plugin.logDebug("CommandExecuteEvent | Player executed an blocked command");
sendBlockedMessage(player);
event.setResult(CommandExecuteEvent.CommandResult.denied());
}
} else {
plugin.logDebug("CommandExecuteEven | Player is not in auth server");
sendBlockedMessage(player);
event.setResult(CommandExecuteEvent.CommandResult.denied());
}
continuation.resume();
});
}
private void sendBlockedMessage(Player player){
String blockedMessage = plugin.config().get().commands().blockedCommandMessage();
if (!blockedMessage.isBlank()){
player.sendMessage(MiniMessage.miniMessage().deserialize(blockedMessage));
}
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2023 AuthMeVelocity Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package io.github._4drian3d.authmevelocity.velocity.listener.input;
import com.google.inject.Inject;
import com.velocitypowered.api.event.EventManager;
import com.velocitypowered.api.event.EventTask;
import com.velocitypowered.api.event.PostOrder;
import com.velocitypowered.api.event.player.TabCompleteEvent;
import io.github._4drian3d.authmevelocity.velocity.AuthMeVelocityPlugin;
import io.github._4drian3d.authmevelocity.velocity.listener.Listener;
public class TabCompleteListener implements Listener<TabCompleteEvent> {
@Inject
private AuthMeVelocityPlugin plugin;
@Inject
private EventManager eventManager;
@Override
public void register() {
eventManager.register(plugin, TabCompleteEvent.class, PostOrder.FIRST, this);
}
@Override
public EventTask executeAsync(final TabCompleteEvent event) {
return EventTask.async(() -> {
if (plugin.isLogged(event.getPlayer())) {
plugin.logDebug("TabCompleteEvent | Player is already logged");
return;
}
final String command = event.getPartialMessage();
for (final String allowed : plugin.config().get().commands().allowedCommands()) {
if (allowed.startsWith(command)) {
return;
}
}
plugin.logDebug("TabCompleteEvent | Not allowed tab-completion");
event.getSuggestions().clear();
});
}
}