diff --git a/bans-api/src/main/java/space/arim/libertybans/api/select/PunishmentSelector.java b/bans-api/src/main/java/space/arim/libertybans/api/select/PunishmentSelector.java index 0e2bb1c44..bf6709bfa 100644 --- a/bans-api/src/main/java/space/arim/libertybans/api/select/PunishmentSelector.java +++ b/bans-api/src/main/java/space/arim/libertybans/api/select/PunishmentSelector.java @@ -1,6 +1,6 @@ /* * LibertyBans - * Copyright © 2022 Anand Beh + * Copyright © 2024 Anand Beh * * LibertyBans is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -77,6 +77,9 @@ public interface PunishmentSelector { * the player's UUID and IP. It may be, the player's IP is banned, the player's UUID is banned, * or the player has played on a banned IP and that IP is banned while strict address enforcement is enabled.
*
+ * For maximum accuracy, the UUID and IP address pair should be taken from an actual user who has logged on before. + * Due to specifics in terms of how applicability is computed, some punishments + *
* By default, the server's configured address strictness is used, but this may be changed if desired. * * @param uuid the uuid of the user for whom to select applicable punishments diff --git a/bans-core/src/main/java/space/arim/libertybans/core/database/sql/ApplicableViewFields.java b/bans-core/src/main/java/space/arim/libertybans/core/database/sql/ApplicableViewFields.java index 2933361c4..9f42c0a15 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/database/sql/ApplicableViewFields.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/database/sql/ApplicableViewFields.java @@ -1,6 +1,6 @@ /* * LibertyBans - * Copyright © 2023 Anand Beh + * Copyright © 2024 Anand Beh * * LibertyBans is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -31,7 +31,6 @@ import space.arim.libertybans.core.scope.ScopeType; import java.time.Instant; -import java.util.Objects; import java.util.UUID; public record ApplicableViewFields scopeType() { } public Field uuid() { - return Objects.requireNonNull(fieldSupplier.field11(), "uuid field does not exist"); + return fieldSupplier.field11(); + } + + public Field address() { + return fieldSupplier.field12(); } } diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/EnforcementConfig.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/EnforcementConfig.java index fe27bc98d..083c88b70 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/EnforcementConfig.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/EnforcementConfig.java @@ -1,6 +1,6 @@ /* * LibertyBans - * Copyright © 2022 Anand Beh + * Copyright © 2024 Anand Beh * * LibertyBans is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -19,6 +19,7 @@ package space.arim.libertybans.core.selector; +import java.util.List; import java.util.Set; import space.arim.dazzleconf.annote.ConfComments; @@ -138,4 +139,29 @@ interface AltAccountExpiration { long expirationTimeDays(); } + + @ConfKey("alts-registry") + @SubSection + AltsRegistry altsRegistry(); + + @ConfHeader({"Controls if all servers should register the IP address of the player connecting."}) + interface AltsRegistry { + + @ConfComments({"The server names in this list will be excluded from associating the IP address of the player connecting.", + "Please note that the server's name in the list should be the same as the ones in your proxy configuration.", + "This is intended to be used by LibertyBans proxy installations.", + "If you are planning to use this feature, you MUST enable the 'enforce-server-switch' option." + }) + @ConfKey("servers-without-ip-registration") + @DefaultStrings({"auth"}) + List serversWithoutRegistration(); + + @ConfComments({"If you want to register the IP address of the player connecting, set this to true.", + "If you are running a proxy and don't want to register the IP when players connect, ", + "set this to false and add the authentication servers' names in the list above.", + "If this is a backend server, set it to false; if it's an authentication server, set to true."}) + @ConfKey("should-register-on-connection)") + @ConfDefault.DefaultBoolean(true) + boolean shouldRegisterOnConnection(); + } } diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java index a47fadb97..55d0f4c56 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java @@ -1,6 +1,6 @@ /* * LibertyBans - * Copyright © 2023 Anand Beh + * Copyright © 2024 Anand Beh * * LibertyBans is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -22,6 +22,8 @@ import jakarta.inject.Inject; import jakarta.inject.Provider; import net.kyori.adventure.text.Component; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.jooq.DSLContext; import space.arim.libertybans.api.NetworkAddress; import space.arim.libertybans.api.PunishmentType; import space.arim.libertybans.api.punish.Punishment; @@ -74,14 +76,17 @@ CentralisedFuture executeAndCheckConnection(UUID uuid, String name, N Set scopes, SelectorImpl selector) { return queryExecutor.get().queryWithRetry((context, transaction) -> { Instant currentTime = time.currentTimestamp(); + EnforcementConfig config = configs.getMainConfig().enforcement(); - Association association = new Association(uuid, context); - association.associateCurrentName(name, currentTime); - association.associateCurrentAddress(address, currentTime); + boolean recordUserAssociation = config.altsRegistry().shouldRegisterOnConnection(); + if (recordUserAssociation) { + doAssociation(uuid, name, address, currentTime, context); + } Punishment ban = selector.selectionByApplicabilityBuilder(uuid, address) .type(PunishmentType.BAN) .scopes(SelectionPredicate.matchingAnyOf(scopes)) + .canAssumeUserRecorded(recordUserAssociation) .build() .findFirstSpecificPunishment(context, () -> currentTime, SortPunishments.LATEST_END_DATE_FIRST); if (ban != null) { @@ -113,4 +118,42 @@ CentralisedFuture executeAndCheckConnection(UUID uuid, String name, N return futuresFactory.completedFuture(null); }); } + + public CentralisedFuture<@Nullable Component> checkServerSwitch(UUID uuid, String name, NetworkAddress address, + String destinationServer, ServerScope serverScope, + SelectorImpl selector) { + if (!configs.getMainConfig().platforms().proxies().enforceServerSwitch()) { + return null; + } + + return queryExecutor.get().queryWithRetry((context, transaction) -> { + Instant currentTime = time.currentTimestamp(); + var altsRegistry = configs.getMainConfig().enforcement().altsRegistry(); + boolean registerOnConnection = altsRegistry.shouldRegisterOnConnection(); + List serversWithoutAssociation = altsRegistry.serversWithoutRegistration(); + + if (!registerOnConnection && !serversWithoutAssociation.contains(destinationServer)) { + doAssociation(uuid, name, address, currentTime, context); + } + + return selector.selectionByApplicabilityBuilder(uuid, address) + .type(PunishmentType.BAN) + .scopes(SelectionPredicate.matchingOnly(serverScope)) + .build() + .findFirstSpecificPunishment(context, () -> currentTime, SortPunishments.LATEST_END_DATE_FIRST); + }).thenCompose((punishment) -> { + if (punishment != null) { + return formatter.getPunishmentMessage(punishment); + } else { + return futuresFactory.completedFuture(null); + } + }); + } + + private void doAssociation(UUID uuid, String name, NetworkAddress address, + Instant currentTime, DSLContext context) { + Association association = new Association(uuid, context); + association.associateCurrentName(name, currentTime); + association.associateCurrentAddress(address, currentTime); + } } diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/Guardian.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/Guardian.java index 488bcd127..14c20e01e 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/Guardian.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/Guardian.java @@ -35,9 +35,9 @@ public interface Guardian { * Adds the uuid and name to the local fast cache, queries for an applicable ban, and formats the * ban reason as the punishment message. * - * @param uuid the player's uuid - * @param name the player's name - * @param address the player's network address + * @param uuid the player's uuid + * @param name the player's name + * @param address the player's network address * @return a future which yields the punishment message if denied, else null if allowed */ CentralisedFuture<@Nullable Component> executeAndCheckConnection(UUID uuid, String name, NetworkAddress address); @@ -63,11 +63,27 @@ public interface Guardian { * Queries for an applicable ban, and formats the ban reason as the punishment message. * * @param uuid the player's uuid + * @param name the player's name * @param address the player's network address * @param destinationServer the player's destination server * @return a future which yields the punishment message if denied, else null if allowed */ - CentralisedFuture<@Nullable Component> checkServerSwitch(UUID uuid, InetAddress address, String destinationServer); + CentralisedFuture<@Nullable Component> checkServerSwitch(UUID uuid, String name, NetworkAddress address, String destinationServer); + + /** + * Enforces a server switch, returning a punishment message if denied, null if allowed.
+ *
+ * Queries for an applicable ban, and formats the ban reason as the punishment message. + * + * @param uuid the player's uuid + * @param name the player's name + * @param address the player's network address + * @param destinationServer the player's destination server + * @return a future which yields the punishment message if denied, else null if allowed + */ + default CentralisedFuture<@Nullable Component> checkServerSwitch(UUID uuid, String name, InetAddress address, String destinationServer) { + return checkServerSwitch(uuid, name, NetworkAddress.of(address), destinationServer); + } /** * Enforces a chat message or executed command, returning a punishment message if denied, null if allowed.
diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/IntelligentGuardian.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/IntelligentGuardian.java index 632dfc7c7..ed7510b88 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/IntelligentGuardian.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/IntelligentGuardian.java @@ -24,9 +24,7 @@ import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.Nullable; import space.arim.libertybans.api.NetworkAddress; -import space.arim.libertybans.api.PunishmentType; import space.arim.libertybans.api.scope.ScopeManager; -import space.arim.libertybans.api.select.SortPunishments; import space.arim.libertybans.core.config.Configs; import space.arim.libertybans.core.config.InternalFormatter; import space.arim.libertybans.core.selector.cache.MuteCache; @@ -34,7 +32,6 @@ import space.arim.omnibus.util.concurrent.CentralisedFuture; import space.arim.omnibus.util.concurrent.FactoryOfTheFuture; -import java.net.InetAddress; import java.util.UUID; import java.util.concurrent.CompletionException; import java.util.concurrent.TimeUnit; @@ -98,23 +95,12 @@ private static Function timeoutHandler(String where) { } @Override - public CentralisedFuture<@Nullable Component> checkServerSwitch(UUID uuid, InetAddress address, + public CentralisedFuture<@Nullable Component> checkServerSwitch(UUID uuid, String name, NetworkAddress address, String destinationServer) { - if (!configs.getMainConfig().platforms().proxies().enforceServerSwitch()) { - return futuresFactory.completedFuture(null); - } return selector - .selectionByApplicabilityBuilder(uuid, address) - .type(PunishmentType.BAN) - .scope(scopeManager.specificScope(destinationServer)) - .build() - .getFirstSpecificPunishment(SortPunishments.LATEST_END_DATE_FIRST) - .thenCompose((punishment) -> { - if (punishment.isEmpty()) { - return futuresFactory.completedFuture(null); - } - return formatter.getPunishmentMessage(punishment.get()); - }) + .executeAndCheckServerSwitch( + uuid, name, address, destinationServer + ) .toCompletableFuture() .orTimeout(12, TimeUnit.SECONDS) .exceptionally(timeoutHandler("server switch")); diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/InternalSelector.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/InternalSelector.java index bb3a43cad..82542ae53 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/InternalSelector.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/InternalSelector.java @@ -42,14 +42,26 @@ public interface InternalSelector extends PunishmentSelector { /** * Checks a player connection's in a single connection query, enforcing any applicable bans, * connection limits, and dealing out alt checks - * - * @param uuid the player uuid - * @param name the player name - * @param address the player address - * @param scopes the server scopes to include in the selection query + * + * @param uuid the player uuid + * @param name the player name + * @param address the player address + * @param scopes the server scopes to include in the selection query * @return a future which yields the denial message, or null if there is none */ CentralisedFuture executeAndCheckConnection(UUID uuid, String name, NetworkAddress address, Set scopes); + /** + * Checks a player connection's in a single connection query, enforcing any applicable bans if + * enforce server switch is enabled. + * + * @param uuid the player uuid + * @param name the player name + * @param address the player address + * @param destinationServer the server the player is switching to + * @return a future which yields the denial message, or null if there is none + */ + CentralisedFuture executeAndCheckServerSwitch(UUID uuid, String name, NetworkAddress address, + String destinationServer); } diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectionByApplicabilityBuilderImpl.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectionByApplicabilityBuilderImpl.java index cbb0f6747..26551cb4b 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectionByApplicabilityBuilderImpl.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectionByApplicabilityBuilderImpl.java @@ -1,6 +1,6 @@ /* * LibertyBans - * Copyright © 2023 Anand Beh + * Copyright © 2024 Anand Beh * * LibertyBans is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -39,6 +39,7 @@ public final class SelectionByApplicabilityBuilderImpl private final NetworkAddress address; private AddressStrictness strictness; private final AddressStrictness defaultStrictness; + private boolean potentialNewEntrant; SelectionByApplicabilityBuilderImpl(SelectionResources resources, UUID uuid, NetworkAddress address, AddressStrictness defaultStrictness) { @@ -68,7 +69,7 @@ SelectionByApplicabilityBuilder yieldSelf() { @Override SelectionByApplicability buildWith(SelectionBaseImpl.Details details) { return new SelectionByApplicabilityImpl( - details, resources, uuid, address, strictness + details, resources, uuid, address, strictness, potentialNewEntrant ); } @@ -89,4 +90,17 @@ public SelectionByApplicabilityImpl build() { return (SelectionByApplicabilityImpl) super.build(); } + /** + * For internal use, to accomodate a new user whose UUID and IP address combination + * has not yet been entered to the database. Sets whether this scenario is potential. + * + * @param canAssumeUserRecorded if the user is definitely registered, set to true. True by default. + * @return this builder + */ + public SelectionByApplicabilityBuilderImpl canAssumeUserRecorded(boolean canAssumeUserRecorded) { + // A user is a potential new entrant if we can't assume they're recorded + this.potentialNewEntrant = !canAssumeUserRecorded; + return this; + } + } diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectionByApplicabilityImpl.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectionByApplicabilityImpl.java index 1fc9c87a9..3e95db55d 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectionByApplicabilityImpl.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectionByApplicabilityImpl.java @@ -1,6 +1,6 @@ /* * LibertyBans - * Copyright © 2023 Anand Beh + * Copyright © 2024 Anand Beh * * LibertyBans is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -38,6 +38,7 @@ import java.util.UUID; import static org.jooq.impl.DSL.inline; +import static org.jooq.impl.DSL.or; import static space.arim.libertybans.core.schema.tables.StrictLinks.STRICT_LINKS; public final class SelectionByApplicabilityImpl extends SelectionBaseSQL implements SelectionByApplicability { @@ -45,13 +46,16 @@ public final class SelectionByApplicabilityImpl extends SelectionBaseSQL impleme private final UUID uuid; private final NetworkAddress address; private final AddressStrictness strictness; + private final boolean potentialNewEntrant; SelectionByApplicabilityImpl(Details details, SelectionResources resources, - UUID uuid, NetworkAddress address, AddressStrictness strictness) { + UUID uuid, NetworkAddress address, AddressStrictness strictness, + boolean potentialNewEntrant) { super(details, resources); this.uuid = Objects.requireNonNull(uuid, "uuid"); this.address = Objects.requireNonNull(address, "address"); this.strictness = Objects.requireNonNull(strictness, "strictness"); + this.potentialNewEntrant = potentialNewEntrant; } @Override @@ -69,6 +73,16 @@ public AddressStrictness getAddressStrictness() { return strictness; } + /* + If the potentialNewEntrant flag is set, our task becomes significantly more complicated. + We now have to account for the enforcement of non-lenient address strictness by acting as if + the user had their IP address recorded already. This means attaching additional predication + to scans for IP-based punishments and patching over the applicability links we are accustomed + to having the database account for. + + Thanks to SnakeAmazing for providing this marvelous intellectual puzzle. + */ + @Override Query requestQuery(QueryParameters parameters) { PunishmentFields fields = null; @@ -83,21 +97,74 @@ Query requestQuery(QueryParameters parameters) { ApplicableViewFields applView = requestApplicableView(); fields = applView; table = fields.table(); + if (potentialNewEntrant) { + // appl.uuid = uuid + // OR victim_type != 'PLAYER' AND victim_address = address + // + // Note: It must be victim_address and not appl.address + // Exercise for understanding: Why? + // + yield or( + applView.uuid().eq(uuid), + applView.victimType().notEqual(inline(VictimType.PLAYER)) + .and(applView.victimAddress().eq(address)) + ); + } yield applView.uuid().eq(uuid); // appl.uuid = uuid } case STERN -> { + if (potentialNewEntrant) { + ApplicableViewFields applView = requestApplicableView(); + fields = applView; + table = fields + .table() + .leftJoin(STRICT_LINKS) + .on(applView.uuid().eq(STRICT_LINKS.UUID1)); + // appl.uuid = uuid # NORMAL + // OR victim_type != 'PLAYER' AND ( + // appl.address = address # NORMAL + STERN + // OR strict_links.uuid2 IS NOT NULL AND strict_links.uuid2 = uuid # STERN + // ) + // + // Note: The last predicate must use appl.address and not victim_address + // Exercise for understanding: Why? + // + yield or( + applView.uuid().eq(uuid), + applView.victimType().notEqual(inline(VictimType.PLAYER)).and(or( + STRICT_LINKS.UUID2.isNotNull().and(STRICT_LINKS.UUID2.eq(uuid)), + applView.address().eq(address) + )) + ); + } ApplicableViewFields applView = requestApplicableView(); fields = applView; table = fields .table() .innerJoin(STRICT_LINKS) .on(applView.uuid().eq(STRICT_LINKS.UUID1)); - // appl.uuid = strict_links.uuid1 = uuid - // OR victim_type != 'PLAYER' AND strict_links.uuid2 = uuid + // appl.uuid = strict_links.uuid1 = uuid # NORMAL + // OR victim_type != 'PLAYER' AND strict_links.uuid2 = uuid # STERN yield STRICT_LINKS.UUID1.eq(uuid).or( STRICT_LINKS.UUID2.eq(uuid).and(applView.victimType().notEqual(inline(VictimType.PLAYER)))); } case STRICT -> { + if (potentialNewEntrant) { + ApplicableViewFields applView = requestApplicableView(); + fields = applView; + table = fields + .table() + .leftJoin(STRICT_LINKS) + .on(applView.uuid().eq(STRICT_LINKS.UUID1)); + // appl.uuid = uuid # NORMAL + // OR appl.address = address # NORMAL + STRICT + // OR strict_links.uuid2 IS NOT NULL AND strict_links.uuid2 = uuid # STRICT + yield or( + applView.uuid().eq(uuid), + applView.address().eq(address), + STRICT_LINKS.UUID2.isNotNull().and(STRICT_LINKS.UUID2.eq(uuid)) + ); + } ApplicableViewFields applView = requestApplicableView(); fields = applView; table = fields diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectorImpl.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectorImpl.java index 630e97fb1..110e30904 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectorImpl.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectorImpl.java @@ -26,6 +26,7 @@ import space.arim.libertybans.api.NetworkAddress; import space.arim.libertybans.api.PunishmentType; import space.arim.libertybans.api.punish.Punishment; +import space.arim.libertybans.api.scope.ScopeManager; import space.arim.libertybans.api.scope.ServerScope; import space.arim.libertybans.api.select.AddressStrictness; import space.arim.libertybans.api.select.SelectionOrderBuilder; @@ -47,15 +48,18 @@ public class SelectorImpl implements InternalSelector { private final Gatekeeper gatekeeper; private final Provider muteCache; private final SelectionResources resources; + private final ScopeManager scopeManager; @Inject public SelectorImpl(Configs configs, IDImpl idImpl, Gatekeeper gatekeeper, - Provider muteCache, SelectionResources resources) { + Provider muteCache, SelectionResources resources, + ScopeManager scopeManager) { this.configs = configs; this.idImpl = idImpl; this.gatekeeper = gatekeeper; this.muteCache = muteCache; this.resources = resources; + this.scopeManager = scopeManager; } @Override @@ -112,6 +116,13 @@ public CentralisedFuture executeAndCheckConnection(UUID uuid, String return gatekeeper.executeAndCheckConnection(uuid, name, address, scopes, this); } + @Override + public CentralisedFuture executeAndCheckServerSwitch(UUID uuid, String name, NetworkAddress address, + String destinationServer) { + return gatekeeper.checkServerSwitch(uuid, name, address, destinationServer, + scopeManager.specificScope(destinationServer), this); + } + @Override public ReactionStage> getCachedMute(UUID uuid, NetworkAddress address) { Objects.requireNonNull(uuid, "uuid"); diff --git a/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/ConnectionListener.java b/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/ConnectionListener.java index ef24d4848..231ac9a94 100644 --- a/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/ConnectionListener.java +++ b/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/ConnectionListener.java @@ -108,7 +108,7 @@ public void onServerSwitch(ServerConnectEvent event) { InetAddress address = addressReporter.getAddress(player); Component message = guardian.checkServerSwitch( - player.getUniqueId(), address, event.getTarget().getName() + player.getUniqueId(), player.getName(), address, event.getTarget().getName() ).join(); if (message != null) { event.setCancelled(true); diff --git a/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/ConnectionListener.java b/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/ConnectionListener.java index ce019f2c6..a09a74a3f 100644 --- a/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/ConnectionListener.java +++ b/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/ConnectionListener.java @@ -68,6 +68,7 @@ public EventTask onConnect(LoginEvent event) { return null; } Player player = event.getPlayer(); + return EventTask.resumeWhenComplete(guardian.executeAndCheckConnection( player.getUniqueId(), player.getUsername(), player.getRemoteAddress().getAddress() ).thenAccept((message) -> { @@ -91,7 +92,8 @@ public EventTask onServerSwitch(ServerPreConnectEvent event) { } Player player = event.getPlayer(); return EventTask.resumeWhenComplete(guardian.checkServerSwitch( - player.getUniqueId(), player.getRemoteAddress().getAddress(), destination.getServerInfo().getName() + player.getUniqueId(), player.getUsername(), player.getRemoteAddress().getAddress(), + destination.getServerInfo().getName() ).thenAccept((message) -> { if (message != null) { event.setResult(ServerPreConnectEvent.ServerResult.denied());