diff --git a/README.md b/README.md
index 9df742775..f0d6fea6b 100644
--- a/README.md
+++ b/README.md
@@ -75,8 +75,8 @@ Free software and high quality, LibertyBans is the best-designed punishment plug
Supported platforms:
-* Spigot / Paper, including Folia
-* BungeeCord
+* Spigot / Paper (+Folia)
+* BungeeCord / Waterfall
* Sponge
* Velocity
@@ -98,3 +98,5 @@ The developer API is extensive. LibertyBans does not recommend developers mess w
### License
LibertyBans is licensed under the GNU AGPL v3. See the license file for more information.
+
+[![GNU AGPL Logo](https://www.gnu.org/graphics/agplv3-155x51.png)](https://www.gnu.org/licenses/agpl-3.0.en.html)
diff --git a/bans-core/src/main/java/space/arim/libertybans/core/PillarOneBindModuleMinusConfigs.java b/bans-core/src/main/java/space/arim/libertybans/core/PillarOneBindModuleMinusConfigs.java
index cb4ad9264..4bac77b71 100644
--- a/bans-core/src/main/java/space/arim/libertybans/core/PillarOneBindModuleMinusConfigs.java
+++ b/bans-core/src/main/java/space/arim/libertybans/core/PillarOneBindModuleMinusConfigs.java
@@ -55,7 +55,7 @@ public GlobalEnforcement enforcement(StandardGlobalEnforcement enforcement) {
return enforcement;
}
- public LocalEnforcer enforcer(StandardLocalEnforcer enforcer) {
+ public LocalEnforcer enforcer(StandardLocalEnforcer> enforcer) {
return enforcer;
}
diff --git a/bans-core/src/main/java/space/arim/libertybans/core/config/MainConfig.java b/bans-core/src/main/java/space/arim/libertybans/core/config/MainConfig.java
index 576632415..791138837 100644
--- a/bans-core/src/main/java/space/arim/libertybans/core/config/MainConfig.java
+++ b/bans-core/src/main/java/space/arim/libertybans/core/config/MainConfig.java
@@ -193,16 +193,20 @@ interface Sponge {
@ConfHeader("Related to game servers such as Spigot, Paper, and Sponge")
interface GameServers {
- @ConfKey("kick-via-plugin-messaging")
+ @ConfKey("use-plugin-messaging")
@ConfComments({
"This option is relevant for backend servers running within a network (BungeeCord or Velocity).",
- "It instructs the proxy to kick the player from the network via plugin messaging.",
+ "It enables the use of plugin messaging, such as for:",
+ " - Kicking the player from the entire network",
+ " - Detecting the name of the backend server for use with server scopes",
+ " - Synchronizing punishments across instances, depending on the mode in the sql.yml",
"",
- "If enabled, the player will NOT be kicked by the backend server, so you MUST use a proxy",
- "otherwise players will not be kicked at all."
+ "DO NOT enable this option if you do not run a network. Otherwise, you create a security vulnerability",
+ "whereby players can pretend to be coming from a proxy, evading kicks and sending sync messages.",
+ "After changing this option, please perform a restart (/libertybans restart)."
})
@DefaultBoolean(false)
- boolean kickViaPluginMessaging();
+ boolean usePluginMessaging();
}
@@ -212,6 +216,16 @@ interface GameServers {
@ConfHeader("Related to proxies such as BungeeCord and Velocity")
interface Proxies {
+ @ConfKey("multiple-proxy-instances")
+ @ConfComments({
+ "Set this to true to indicate that you are running multiple proxy instances.",
+ "",
+ "It will instruct LibertyBans to perform additional synchronization measures, where applicable."
+ })
+ @DefaultBoolean(false)
+ // Currently unused, but may be utilized later
+ boolean multipleProxyInstances();
+
@ConfKey("enforce-server-switch")
@ConfComments({
"Server-scoped punishments will be enforced by preventing server switches for players connecting ",
diff --git a/bans-core/src/main/java/space/arim/libertybans/core/config/ScopeConfig.java b/bans-core/src/main/java/space/arim/libertybans/core/config/ScopeConfig.java
index a140ac971..e7119bc53 100644
--- a/bans-core/src/main/java/space/arim/libertybans/core/config/ScopeConfig.java
+++ b/bans-core/src/main/java/space/arim/libertybans/core/config/ScopeConfig.java
@@ -80,12 +80,15 @@ interface ServerName {
@ConfKey("auto-detect")
@ConfComments({
"By default, we try to detect the name of this backend server using plugin messaging.",
- "On a proxy, the detected name becomes 'proxy'.",
+ "Make sure 'use-plugin-messaging' is enabled in the config.yml for this detection to succeed.",
+ "",
+ "If running a proxy, the detected name becomes 'proxy'.",
"",
"Plugin messaging requires at least one player to have logged into the backend server.",
"Auto detection may fail, for example, if you ban someone through the console but no one has joined yet.",
"",
- "To disable auto detection, set this to false then configure 'override-value' to the server name you wish to use."
+ "To disable auto detection, set this to false then configure 'override-value' to the server name you wish to use.",
+ "Re-enabling this option may require a restart (/libertybans restart)"
})
@ConfDefault.DefaultBoolean(true)
boolean autoDetect();
diff --git a/bans-core/src/main/java/space/arim/libertybans/core/database/sql/ScopeCondition.java b/bans-core/src/main/java/space/arim/libertybans/core/database/sql/ScopeCondition.java
index fe4f31b4b..c503fed8e 100644
--- a/bans-core/src/main/java/space/arim/libertybans/core/database/sql/ScopeCondition.java
+++ b/bans-core/src/main/java/space/arim/libertybans/core/database/sql/ScopeCondition.java
@@ -22,8 +22,6 @@
import org.jooq.Condition;
import space.arim.libertybans.api.scope.ServerScope;
import space.arim.libertybans.core.scope.InternalScopeManager;
-import space.arim.libertybans.core.scope.ScopeParsing;
-import space.arim.libertybans.core.scope.ScopeType;
import static org.jooq.impl.DSL.noCondition;
@@ -32,7 +30,7 @@ public record ScopeCondition(ScopeFields scopeFields, InternalScopeManager scope
@Override
public Condition matchesValue(ServerScope scope) {
- return new ScopeParsing().deconstruct(scope, (type, value) -> {
+ return scopeManager.deconstruct(scope, (type, value) -> {
Condition typeMatches = scopeFields.scopeType().eq(type);
Condition valueMatches = switch (type) {
case GLOBAL -> noCondition();
diff --git a/bans-core/src/main/java/space/arim/libertybans/core/env/AbstractEnvEnforcer.java b/bans-core/src/main/java/space/arim/libertybans/core/env/AbstractEnvEnforcer.java
index 1e06e6b68..4b08306a6 100644
--- a/bans-core/src/main/java/space/arim/libertybans/core/env/AbstractEnvEnforcer.java
+++ b/bans-core/src/main/java/space/arim/libertybans/core/env/AbstractEnvEnforcer.java
@@ -21,11 +21,17 @@
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentLike;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import space.arim.api.env.AudienceRepresenter;
import space.arim.libertybans.core.config.InternalFormatter;
+import space.arim.libertybans.core.env.message.PluginMessage;
+import space.arim.omnibus.util.ThisClass;
import space.arim.omnibus.util.concurrent.CentralisedFuture;
import space.arim.omnibus.util.concurrent.FactoryOfTheFuture;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
@@ -36,6 +42,8 @@ public abstract class AbstractEnvEnforcer
implements EnvEnforcer
{
private final Interlocutor interlocutor;
private final AudienceRepresenter super P> audienceRepresenter;
+ private static final Logger logger = LoggerFactory.getLogger(ThisClass.get());
+
protected AbstractEnvEnforcer(FactoryOfTheFuture futuresFactory, InternalFormatter formatter,
Interlocutor interlocutor, AudienceRepresenter super P> audienceRepresenter) {
this.futuresFactory = Objects.requireNonNull(futuresFactory, "futuresFactory");
@@ -83,10 +91,30 @@ private CentralisedFuture sendToThoseWithPermissionNoPrefix(String permiss
}
};
}
- return doForAllPlayers(callback);
+ return doForAllPlayers((players) -> players.forEach(callback));
+ }
+
+ @Override
+ public final void sendPluginMessage(P player, PluginMessage pluginMessage, D data) {
+ if (!sendPluginMessageIfListening(player, pluginMessage, data)) {
+ logger.error(
+ "Attempted to send plugin message to {}, but the appropriate channel is not accepted. " +
+ "This suggests you enabled use-plugin-messaging in the config.yml, but the player " +
+ "is not connected to a network. Please address this critical security flaw immediately. " +
+ "It leaves your server vulnerable to clients spoofing the plugin messaging channel",
+ player
+ );
+ }
}
- protected abstract CentralisedFuture doForAllPlayers(Consumer callback);
+ /**
+ * Sends a plugin message to the given player if it is accepted by their client
+ *
+ * @param player the player to whom to send the message
+ * @param pluginMessage the plugin message
+ * @return true if sent, false if unsupported
+ */
+ public abstract boolean sendPluginMessageIfListening(P player, PluginMessage pluginMessage, D data);
@Override
public final void sendMessageNoPrefix(P player, ComponentLike message) {
@@ -95,10 +123,16 @@ public final void sendMessageNoPrefix(P player, ComponentLike message) {
@Override
public final CentralisedFuture enforceMatcher(TargetMatcher matcher) {
- return doForAllPlayers((player) -> {
- if (matcher.matches(getUniqueIdFor(player), getAddressFor(player))) {
- matcher.callback().accept(player);
+ return doForAllPlayers((players) -> {
+ List
matchedPlayers = new ArrayList<>();
+ // Some platforms do not provide guarantees about concurrent iteration in presence of kicks
+ // Proxies effectively must, but game server APIs like Bukkit and Sponge need not
+ for (P player : players) {
+ if (matcher.matches(getUniqueIdFor(player), getAddressFor(player))) {
+ matchedPlayers.add(player);
+ }
}
+ matchedPlayers.forEach(matcher.callback());
});
}
diff --git a/bans-core/src/main/java/space/arim/libertybans/core/env/EnvEnforcer.java b/bans-core/src/main/java/space/arim/libertybans/core/env/EnvEnforcer.java
index c899b1bba..eabae3a9f 100644
--- a/bans-core/src/main/java/space/arim/libertybans/core/env/EnvEnforcer.java
+++ b/bans-core/src/main/java/space/arim/libertybans/core/env/EnvEnforcer.java
@@ -20,6 +20,7 @@
package space.arim.libertybans.core.env;
import java.net.InetAddress;
+import java.util.Collection;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
@@ -27,6 +28,7 @@
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentLike;
import space.arim.api.env.annote.PlatformPlayer;
+import space.arim.libertybans.core.env.message.PluginMessage;
import space.arim.omnibus.util.concurrent.CentralisedFuture;
/**
@@ -45,6 +47,7 @@ public interface EnvEnforcer<@PlatformPlayer P> {
*
* @param permission the permission
* @param message the message
+ * @return a future completed when the operation is done
*/
CentralisedFuture sendToThoseWithPermission(String permission, ComponentLike message);
@@ -53,9 +56,18 @@ public interface EnvEnforcer<@PlatformPlayer P> {
*
* @param uuid the uuid
* @param callback the callback
+ * @return a future completed when the operation is done
*/
CentralisedFuture doForPlayerIfOnline(UUID uuid, Consumer callback);
+ /**
+ * Completes an action for all players online
+ *
+ * @param action the action
+ * @return a future completed when the operation is done
+ */
+ CentralisedFuture doForAllPlayers(Consumer> action);
+
/**
* Kicks the given player.
*
@@ -66,6 +78,14 @@ public interface EnvEnforcer<@PlatformPlayer P> {
*/
void kickPlayer(P player, Component message);
+ /**
+ * Sends a plugin message to the given player. Must be used only for proxies.
+ *
+ * @param player the player to whom to send the message
+ * @param pluginMessage the plugin message
+ */
+ void sendPluginMessage(P player, PluginMessage pluginMessage, D data);
+
/**
* Sends a message to the given player. Does not include a prefix.
*
@@ -103,6 +123,16 @@ public interface EnvEnforcer<@PlatformPlayer P> {
*/
InetAddress getAddressFor(P player);
+ /**
+ * Gets the name of a player.
+ *
+ * Must be used within a callback.
+ *
+ * @param player the player
+ * @return the name
+ */
+ String getNameFor(P player);
+
/**
* Determines whether the player has a permission
*
diff --git a/bans-core/src/main/java/space/arim/libertybans/core/env/EnvMessageChannel.java b/bans-core/src/main/java/space/arim/libertybans/core/env/EnvMessageChannel.java
new file mode 100644
index 000000000..b0375dada
--- /dev/null
+++ b/bans-core/src/main/java/space/arim/libertybans/core/env/EnvMessageChannel.java
@@ -0,0 +1,74 @@
+/*
+ * LibertyBans
+ * Copyright © 2023 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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * LibertyBans 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with LibertyBans. If not, see
+ * and navigate to version 3 of the GNU Affero General Public License.
+ */
+
+package space.arim.libertybans.core.env;
+
+import space.arim.libertybans.core.env.message.PluginMessage;
+
+import java.util.function.Consumer;
+
+public interface EnvMessageChannel {
+
+ /**
+ * Installs a platform specific handler
+ *
+ * @param handler the handler
+ */
+ void installHandler(H handler);
+
+ /**
+ * Uninstalls a platform specific handler
+ *
+ * @param handler the handler
+ */
+ void uninstallHandler(H handler);
+
+ /**
+ * Wraps an acceptor as a platform specific handler. Should be called once.
+ *
+ * @param acceptor the acceptor
+ * @param pluginMessage the plugin message it handles
+ * @return the handler
+ * @param the type of the handler
+ */
+ H createHandler(Consumer acceptor, PluginMessage, R> pluginMessage);
+
+ static void parameterize(EnvMessageChannel messageChannel, Consumer> action) {
+ action.accept(messageChannel);
+ }
+
+ final class NoOp implements EnvMessageChannel {
+
+ @Override
+ public void installHandler(Void handler) {
+
+ }
+
+ @Override
+ public void uninstallHandler(Void handler) {
+
+ }
+
+ @Override
+ public Void createHandler(Consumer acceptor, PluginMessage, R> pluginMessage) {
+ return null;
+ }
+ }
+
+}
diff --git a/bans-core/src/main/java/space/arim/libertybans/core/env/InstanceType.java b/bans-core/src/main/java/space/arim/libertybans/core/env/InstanceType.java
new file mode 100644
index 000000000..3f541d830
--- /dev/null
+++ b/bans-core/src/main/java/space/arim/libertybans/core/env/InstanceType.java
@@ -0,0 +1,26 @@
+/*
+ * LibertyBans
+ * Copyright © 2023 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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * LibertyBans 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with LibertyBans. If not, see
+ * and navigate to version 3 of the GNU Affero General Public License.
+ */
+
+package space.arim.libertybans.core.env;
+
+public enum InstanceType {
+ GAME_SERVER,
+ PROXY,
+ STANDALONE
+}
diff --git a/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/PluginMessageData.java b/bans-core/src/main/java/space/arim/libertybans/core/env/PluginMessageAsBytes.java
similarity index 91%
rename from bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/PluginMessageData.java
rename to bans-core/src/main/java/space/arim/libertybans/core/env/PluginMessageAsBytes.java
index ed61d78fa..390ad6e82 100644
--- a/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/PluginMessageData.java
+++ b/bans-core/src/main/java/space/arim/libertybans/core/env/PluginMessageAsBytes.java
@@ -17,7 +17,7 @@
* and navigate to version 3 of the GNU Affero General Public License.
*/
-package space.arim.libertybans.env.spigot;
+package space.arim.libertybans.core.env;
import space.arim.libertybans.core.env.message.PluginMessage;
import space.arim.libertybans.core.env.message.PluginMessageInput;
@@ -33,9 +33,9 @@
import java.io.UncheckedIOException;
import java.util.Optional;
-record PluginMessageData(PluginMessage pluginMessage) {
+public record PluginMessageAsBytes(PluginMessage pluginMessage) {
- byte[] generateBytes(D data) {
+ public byte[] generateBytes(D data) {
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
DataOutputStream dataOutput = new DataOutputStream(outputStream)) {
@@ -47,7 +47,7 @@ byte[] generateBytes(D data) {
}
}
- Optional readBytes(byte[] data) {
+ public Optional readBytes(byte[] data) {
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
DataInputStream dataInput = new DataInputStream(inputStream)) {
diff --git a/bans-core/src/main/java/space/arim/libertybans/core/punish/StandardLocalEnforcer.java b/bans-core/src/main/java/space/arim/libertybans/core/punish/StandardLocalEnforcer.java
index 1f81e6a56..a8413fc01 100644
--- a/bans-core/src/main/java/space/arim/libertybans/core/punish/StandardLocalEnforcer.java
+++ b/bans-core/src/main/java/space/arim/libertybans/core/punish/StandardLocalEnforcer.java
@@ -25,6 +25,7 @@
import net.kyori.adventure.text.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import space.arim.api.env.annote.PlatformPlayer;
import space.arim.api.jsonchat.adventure.util.ComponentText;
import space.arim.libertybans.api.AddressVictim;
import space.arim.libertybans.api.CompositeVictim;
@@ -47,8 +48,10 @@
import space.arim.libertybans.core.env.AdditionalUUIDTargetMatcher;
import space.arim.libertybans.core.env.EnvEnforcer;
import space.arim.libertybans.core.env.ExactTargetMatcher;
+import space.arim.libertybans.core.env.InstanceType;
import space.arim.libertybans.core.env.TargetMatcher;
import space.arim.libertybans.core.env.UUIDTargetMatcher;
+import space.arim.libertybans.core.env.message.KickPlayer;
import space.arim.libertybans.core.punish.permission.PunishmentPermission;
import space.arim.libertybans.core.selector.cache.MuteCache;
import space.arim.omnibus.util.ThisClass;
@@ -63,22 +66,24 @@
import static space.arim.libertybans.core.schema.tables.StrictLinks.STRICT_LINKS;
@Singleton
-public final class StandardLocalEnforcer implements LocalEnforcer {
+public final class StandardLocalEnforcer<@PlatformPlayer P> implements LocalEnforcer {
+ private final InstanceType instanceType;
private final Configs configs;
private final FactoryOfTheFuture futuresFactory;
private final Provider queryExecutor;
private final PunishmentSelector selector;
private final InternalFormatter formatter;
+ private final EnvEnforcer envEnforcer;
private final MuteCache muteCache;
- private final EnvEnforcer> envEnforcer;
private static final Logger logger = LoggerFactory.getLogger(ThisClass.get());
@Inject
- public StandardLocalEnforcer(Configs configs, FactoryOfTheFuture futuresFactory,
+ public StandardLocalEnforcer(InstanceType instanceType, Configs configs, FactoryOfTheFuture futuresFactory,
Provider queryExecutor, PunishmentSelector selector,
- InternalFormatter formatter, EnvEnforcer> envEnforcer, MuteCache muteCache) {
+ InternalFormatter formatter, EnvEnforcer envEnforcer, MuteCache muteCache) {
+ this.instanceType = instanceType;
this.configs = configs;
this.futuresFactory = futuresFactory;
this.queryExecutor = queryExecutor;
@@ -95,7 +100,7 @@ public CentralisedFuture enforceWithoutSynchronization(Punishment punishme
PunishmentAdditionSection section = configs.getMessagesConfig().additions().forType(punishment.getType());
- var arrestsAndNotices = new Parameterized<>(envEnforcer).enforceArrestsAndNotices(punishment);
+ var arrestsAndNotices = enforceArrestsAndNotices(punishment);
if (enforcementOptions.broadcasting() == Broadcasting.NONE) {
return arrestsAndNotices;
}
@@ -196,123 +201,120 @@ public CentralisedFuture updateDetailsWithoutSynchronization(long id) {
if (optPunishment.isEmpty()) {
// Possible race condition if punishment is expunged
logger.debug("Tried to update details of non-existent punishment with id {}", id);
- return futuresFactory.completedFuture(null);
+ return completedFuture(null);
}
return updateDetailsWithoutSynchronization(optPunishment.get());
}).toCompletableFuture();
}
- // Enforcement of enacted punishments
+ private CentralisedFuture enforceArrestsAndNotices(Punishment punishment) {
- private class Parameterized {
+ return formatter.getPunishmentMessage(punishment).thenCompose((message) -> {
- private final EnvEnforcer
envEnforcer;
+ Victim victim = punishment.getVictim();
+ Consumer
enforcementCallback = enforcementCallback(punishment, message);
+ AddressStrictness strictness = configs.getMainConfig().enforcement().addressStrictness();
- Parameterized(EnvEnforcer
envEnforcer) {
- this.envEnforcer = envEnforcer;
- }
-
- CentralisedFuture enforceArrestsAndNotices(Punishment punishment) {
-
- return formatter.getPunishmentMessage(punishment).thenCompose((message) -> {
-
- Victim victim = punishment.getVictim();
- Consumer enforcementCallback = enforcementCallback(punishment, message);
- AddressStrictness strictness = configs.getMainConfig().enforcement().addressStrictness();
+ if (victim instanceof PlayerVictim playerVictim) {
+ UUID uuid = playerVictim.getUUID();
+ if (strictness == AddressStrictness.STRICT) {
+ return matchUserPunishmentStrict(uuid, enforcementCallback)
+ .thenCompose(envEnforcer::enforceMatcher);
+ }
+ return envEnforcer.doForPlayerIfOnline(uuid, enforcementCallback);
- if (victim instanceof PlayerVictim playerVictim) {
- UUID uuid = playerVictim.getUUID();
- if (strictness == AddressStrictness.STRICT) {
- return matchUserPunishmentStrict(uuid, enforcementCallback)
- .thenCompose(envEnforcer::enforceMatcher);
- }
- return envEnforcer.doForPlayerIfOnline(uuid, enforcementCallback);
+ } else if (victim instanceof AddressVictim addressVictim) {
+ NetworkAddress address = addressVictim.getAddress();
+ return matchAddressPunishment(strictness, enforcementCallback, address)
+ .thenCompose(envEnforcer::enforceMatcher);
- } else if (victim instanceof AddressVictim addressVictim) {
- NetworkAddress address = addressVictim.getAddress();
- return matchAddressPunishment(strictness, enforcementCallback, address)
- .thenCompose(envEnforcer::enforceMatcher);
+ } else if (victim instanceof CompositeVictim compositeVictim) {
+ UUID uuid = compositeVictim.getUUID();
+ NetworkAddress address = compositeVictim.getAddress();
+ return matchAddressPunishment(strictness, enforcementCallback, address)
+ .thenApply((addressMatcher) -> new AdditionalUUIDTargetMatcher<>(uuid, addressMatcher))
+ .thenCompose(envEnforcer::enforceMatcher);
- } else if (victim instanceof CompositeVictim compositeVictim) {
- UUID uuid = compositeVictim.getUUID();
- NetworkAddress address = compositeVictim.getAddress();
- return matchAddressPunishment(strictness, enforcementCallback, address)
- .thenApply((addressMatcher) -> new AdditionalUUIDTargetMatcher<>(uuid, addressMatcher))
- .thenCompose(envEnforcer::enforceMatcher);
+ } else {
+ throw MiscUtil.unknownVictimType(victim.getType());
+ }
+ });
+ }
+ private Consumer
enforcementCallback(Punishment punishment, Component message) {
+ return switch (punishment.getType()) {
+ case BAN, KICK -> (player) -> {
+ if (instanceType == InstanceType.GAME_SERVER
+ && configs.getMainConfig().platforms().gameServers().usePluginMessaging()) {
+ envEnforcer.sendPluginMessage(
+ player, new KickPlayer(), new KickPlayer.Data(envEnforcer.getNameFor(player), message)
+ );
} else {
- throw MiscUtil.unknownVictimType(victim.getType());
+ envEnforcer.kickPlayer(player, message);
}
- });
- }
-
- private Consumer
enforcementCallback(Punishment punishment, Component message) {
- return switch (punishment.getType()) {
- case BAN, KICK -> (player) -> envEnforcer.kickPlayer(player, message);
- case MUTE -> (player) -> {
- /*
- * Mute enforcement must additionally take into account the mute cache
- */
- UUID uuid = envEnforcer.getUniqueIdFor(player);
- NetworkAddress address = NetworkAddress.of(envEnforcer.getAddressFor(player));
- muteCache.setCachedMute(uuid, address, punishment);
-
- envEnforcer.sendMessageNoPrefix(player, message);
- };
- case WARN -> (player) -> envEnforcer.sendMessageNoPrefix(player, message);
};
- }
-
- private CentralisedFuture> matchAddressPunishment(
- AddressStrictness strictness, Consumer enforcementCallback, NetworkAddress address) {
- return switch (strictness) {
- case LENIENT -> completedFuture(new ExactTargetMatcher<>(address, enforcementCallback));
- case NORMAL -> matchAddressPunishmentNormal(address, enforcementCallback);
- case STERN, STRICT -> matchAddressPunishmentSternOrStrict(address, enforcementCallback);
+ case MUTE -> (player) -> {
+ /*
+ * Mute enforcement must additionally take into account the mute cache
+ */
+ UUID uuid = envEnforcer.getUniqueIdFor(player);
+ NetworkAddress address = NetworkAddress.of(envEnforcer.getAddressFor(player));
+ muteCache.setCachedMute(uuid, address, punishment);
+
+ envEnforcer.sendMessageNoPrefix(player, message);
};
- }
+ case WARN -> (player) -> envEnforcer.sendMessageNoPrefix(player, message);
+ };
+ }
- private CentralisedFuture> matchAddressPunishmentNormal(
- NetworkAddress address, Consumer enforcementCallback) {
- return queryExecutor.get().query(SQLFunction.readOnly((context) -> {
- return context
- .select(ADDRESSES.UUID)
- .from(ADDRESSES)
- .where(ADDRESSES.ADDRESS.eq(address))
- .fetchSet(ADDRESSES.UUID);
- })).thenApply((uuids) -> {
- return new UUIDTargetMatcher<>(uuids, enforcementCallback);
- });
- }
+ private CentralisedFuture> matchAddressPunishment(
+ AddressStrictness strictness, Consumer enforcementCallback, NetworkAddress address) {
+ return switch (strictness) {
+ case LENIENT -> completedFuture(new ExactTargetMatcher<>(address, enforcementCallback));
+ case NORMAL -> matchAddressPunishmentNormal(address, enforcementCallback);
+ case STERN, STRICT -> matchAddressPunishmentSternOrStrict(address, enforcementCallback);
+ };
+ }
- private CentralisedFuture> matchAddressPunishmentSternOrStrict(
- NetworkAddress address, Consumer enforcementCallback) {
- return queryExecutor.get().query(SQLFunction.readOnly((context) -> {
- return context
- .select(STRICT_LINKS.UUID2)
- .from(STRICT_LINKS)
- .innerJoin(ADDRESSES)
- .on(STRICT_LINKS.UUID1.eq(ADDRESSES.UUID))
- .where(ADDRESSES.ADDRESS.eq(address))
- .fetchSet(STRICT_LINKS.UUID2);
- })).thenApply((uuids) -> {
- return new UUIDTargetMatcher<>(uuids, enforcementCallback);
- });
- }
+ private CentralisedFuture> matchAddressPunishmentNormal(
+ NetworkAddress address, Consumer enforcementCallback) {
+ return queryExecutor.get().query(SQLFunction.readOnly((context) -> {
+ return context
+ .select(ADDRESSES.UUID)
+ .from(ADDRESSES)
+ .where(ADDRESSES.ADDRESS.eq(address))
+ .fetchSet(ADDRESSES.UUID);
+ })).thenApply((uuids) -> {
+ return new UUIDTargetMatcher<>(uuids, enforcementCallback);
+ });
+ }
- private CentralisedFuture> matchUserPunishmentStrict(
- UUID uuid, Consumer enforcementCallback) {
- return queryExecutor.get().query(SQLFunction.readOnly((context) -> {
- return context
- .select(STRICT_LINKS.UUID2)
- .from(STRICT_LINKS)
- .where(STRICT_LINKS.UUID1.eq(uuid))
- .fetchSet(STRICT_LINKS.UUID2);
- })).thenApply((uuids) -> {
- return new UUIDTargetMatcher<>(uuids, enforcementCallback);
- });
- }
+ private CentralisedFuture> matchAddressPunishmentSternOrStrict(
+ NetworkAddress address, Consumer enforcementCallback) {
+ return queryExecutor.get().query(SQLFunction.readOnly((context) -> {
+ return context
+ .select(STRICT_LINKS.UUID2)
+ .from(STRICT_LINKS)
+ .innerJoin(ADDRESSES)
+ .on(STRICT_LINKS.UUID1.eq(ADDRESSES.UUID))
+ .where(ADDRESSES.ADDRESS.eq(address))
+ .fetchSet(STRICT_LINKS.UUID2);
+ })).thenApply((uuids) -> {
+ return new UUIDTargetMatcher<>(uuids, enforcementCallback);
+ });
+ }
+ private CentralisedFuture> matchUserPunishmentStrict(
+ UUID uuid, Consumer enforcementCallback) {
+ return queryExecutor.get().query(SQLFunction.readOnly((context) -> {
+ return context
+ .select(STRICT_LINKS.UUID2)
+ .from(STRICT_LINKS)
+ .where(STRICT_LINKS.UUID1.eq(uuid))
+ .fetchSet(STRICT_LINKS.UUID2);
+ })).thenApply((uuids) -> {
+ return new UUIDTargetMatcher<>(uuids, enforcementCallback);
+ });
}
private CentralisedFuture completedFuture(T value) {
diff --git a/bans-core/src/main/java/space/arim/libertybans/core/scope/InternalScopeManager.java b/bans-core/src/main/java/space/arim/libertybans/core/scope/InternalScopeManager.java
index f7342cb85..b54f76eaf 100644
--- a/bans-core/src/main/java/space/arim/libertybans/core/scope/InternalScopeManager.java
+++ b/bans-core/src/main/java/space/arim/libertybans/core/scope/InternalScopeManager.java
@@ -50,7 +50,7 @@ public interface InternalScopeManager extends ScopeManager {
*
* @return whether to detect the server name
*/
- boolean shouldDetectServerName();
+ boolean serverNameUndetected();
/**
* Sets the automatically detected name of this server instance
diff --git a/bans-core/src/main/java/space/arim/libertybans/core/scope/ServerNameListenerBase.java b/bans-core/src/main/java/space/arim/libertybans/core/scope/ServerNameListenerBase.java
new file mode 100644
index 000000000..f7ae3bb6a
--- /dev/null
+++ b/bans-core/src/main/java/space/arim/libertybans/core/scope/ServerNameListenerBase.java
@@ -0,0 +1,86 @@
+/*
+ * LibertyBans
+ * Copyright © 2023 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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * LibertyBans 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with LibertyBans. If not, see
+ * and navigate to version 3 of the GNU Affero General Public License.
+ */
+
+package space.arim.libertybans.core.scope;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import space.arim.api.env.annote.PlatformPlayer;
+import space.arim.libertybans.core.config.Configs;
+import space.arim.libertybans.core.env.EnvEnforcer;
+import space.arim.libertybans.core.env.EnvMessageChannel;
+import space.arim.libertybans.core.env.InstanceType;
+import space.arim.libertybans.core.env.PlatformListener;
+import space.arim.libertybans.core.env.message.GetServer;
+
+import java.util.function.Consumer;
+
+@Singleton
+public final class ServerNameListenerBase<@PlatformPlayer P, H> implements PlatformListener {
+
+ private final Configs configs;
+ private final InternalScopeManager scopeManager;
+ private final EnvEnforcer envEnforcer;
+ private final EnvMessageChannel envMessageChannel;
+
+ private final H handler;
+
+ @Inject
+ public ServerNameListenerBase(InstanceType instanceType, Configs configs, InternalScopeManager scopeManager,
+ EnvEnforcer envEnforcer, EnvMessageChannel envMessageChannel) {
+ if (instanceType != InstanceType.GAME_SERVER) {
+ throw new IllegalStateException("Cannot use server name listener except for backend game servers");
+ }
+ this.configs = configs;
+ this.scopeManager = scopeManager;
+ this.envEnforcer = envEnforcer;
+ this.envMessageChannel = envMessageChannel;
+ handler = envMessageChannel.createHandler(new ResponseHandler(), new GetServer());
+ }
+
+ @Override
+ public void register() {
+ if (configs.getMainConfig().platforms().gameServers().usePluginMessaging()) {
+ envMessageChannel.installHandler(handler);
+ }
+ }
+
+ @Override
+ public void unregister() {
+ // This should not throw even if the handler is not registered
+ envMessageChannel.uninstallHandler(handler);
+ }
+
+ public void onJoin(P player) {
+ if (configs.getMainConfig().platforms().gameServers().usePluginMessaging()
+ && configs.getScopeConfig().serverName().autoDetect()
+ && scopeManager.serverNameUndetected()) {
+ envEnforcer.sendPluginMessage(player, new GetServer(), null);
+ }
+ }
+
+ final class ResponseHandler implements Consumer {
+
+ @Override
+ public void accept(GetServer.Response response) {
+ scopeManager.detectServerName(response.server());
+ }
+ }
+
+}
diff --git a/bans-core/src/main/java/space/arim/libertybans/core/scope/StandardScopeManager.java b/bans-core/src/main/java/space/arim/libertybans/core/scope/StandardScopeManager.java
index fbdd8192c..42e1957d8 100644
--- a/bans-core/src/main/java/space/arim/libertybans/core/scope/StandardScopeManager.java
+++ b/bans-core/src/main/java/space/arim/libertybans/core/scope/StandardScopeManager.java
@@ -149,8 +149,8 @@ public ServerScope checkScope(ServerScope scope) {
}
@Override
- public boolean shouldDetectServerName() {
- return serverName == null && config().serverName().autoDetect();
+ public boolean serverNameUndetected() {
+ return serverName == null;
}
@Override
diff --git a/bans-core/src/test/java/space/arim/libertybans/core/PillarOneReplacementModule.java b/bans-core/src/test/java/space/arim/libertybans/core/PillarOneReplacementModule.java
index be6af5d12..658f7283e 100644
--- a/bans-core/src/test/java/space/arim/libertybans/core/PillarOneReplacementModule.java
+++ b/bans-core/src/test/java/space/arim/libertybans/core/PillarOneReplacementModule.java
@@ -1,6 +1,6 @@
/*
* LibertyBans
- * Copyright © 2021 Anand Beh
+ * Copyright © 2023 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
@@ -16,6 +16,7 @@
* along with LibertyBans. If not, see
* and navigate to version 3 of the GNU Affero General Public License.
*/
+
package space.arim.libertybans.core;
import jakarta.inject.Singleton;
@@ -34,7 +35,7 @@ public Configs configs(SpecifiedConfigs configs) {
@Singleton
public SettableTime time(ConfigSpec configSpec) {
- return new SettableTimeImpl(configSpec.unixTime());
+ return new SettableTimeImpl(configSpec.unixTimestamp());
}
public Time time(SettableTime time) {
diff --git a/bans-core/src/test/java/space/arim/libertybans/core/service/SettableTime.java b/bans-core/src/test/java/space/arim/libertybans/core/service/SettableTime.java
index 8b1c68352..e8e471478 100644
--- a/bans-core/src/test/java/space/arim/libertybans/core/service/SettableTime.java
+++ b/bans-core/src/test/java/space/arim/libertybans/core/service/SettableTime.java
@@ -1,6 +1,6 @@
/*
* LibertyBans
- * Copyright © 2021 Anand Beh
+ * Copyright © 2023 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
@@ -37,4 +37,11 @@ public interface SettableTime extends Time {
* @param progression the progression
*/
void advanceBy(Duration progression);
+
+ /**
+ * Sets the time back to the original test timestamp
+ *
+ */
+ void reset();
+
}
diff --git a/bans-core/src/test/java/space/arim/libertybans/core/service/SettableTimeImpl.java b/bans-core/src/test/java/space/arim/libertybans/core/service/SettableTimeImpl.java
index 010118069..a2c7d42d1 100644
--- a/bans-core/src/test/java/space/arim/libertybans/core/service/SettableTimeImpl.java
+++ b/bans-core/src/test/java/space/arim/libertybans/core/service/SettableTimeImpl.java
@@ -1,6 +1,6 @@
/*
* LibertyBans
- * Copyright © 2021 Anand Beh
+ * Copyright © 2023 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
@@ -25,10 +25,12 @@
public final class SettableTimeImpl implements SettableTime {
+ private final Instant original;
/** Milliseconds from the epoch */
private final AtomicLong timestamp;
public SettableTimeImpl(Instant timestamp) {
+ original = timestamp;
this.timestamp = new AtomicLong(timestamp.toEpochMilli());
}
@@ -51,4 +53,10 @@ public long currentTime() {
public long arbitraryNanoTime() {
return timestamp.get() * 1_000_000L; // nanoseconds
}
+
+ @Override
+ public void reset() {
+ setTimestamp(original);
+ }
+
}
diff --git a/bans-core/src/test/java/space/arim/libertybans/it/ConfigSpec.java b/bans-core/src/test/java/space/arim/libertybans/it/ConfigSpec.java
index 2d7eb01f7..b9460ae06 100644
--- a/bans-core/src/test/java/space/arim/libertybans/it/ConfigSpec.java
+++ b/bans-core/src/test/java/space/arim/libertybans/it/ConfigSpec.java
@@ -1,6 +1,6 @@
/*
* LibertyBans
- * Copyright © 2021 Anand Beh
+ * Copyright © 2023 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
@@ -16,71 +16,29 @@
* along with LibertyBans. If not, see
* and navigate to version 3 of the GNU Affero General Public License.
*/
+
package space.arim.libertybans.it;
import space.arim.libertybans.core.database.Vendor;
import space.arim.libertybans.api.select.AddressStrictness;
+import space.arim.libertybans.core.env.InstanceType;
import space.arim.libertybans.core.uuid.ServerType;
import java.time.Instant;
import java.util.Objects;
-public final class ConfigSpec {
-
- private final Vendor vendor;
- private final AddressStrictness addressStrictness;
- private final ServerType serverType;
- private final long unixTime;
-
- ConfigSpec(Vendor vendor, AddressStrictness addressStrictness, ServerType serverType, long unixTime) {
- this.vendor = Objects.requireNonNull(vendor, "vendor");
- this.addressStrictness = Objects.requireNonNull(addressStrictness, "addressStrictness");
- this.serverType = Objects.requireNonNull(serverType, "serverType");
- this.unixTime = unixTime;
- }
-
- public Vendor vendor() {
- return vendor;
- }
-
- public AddressStrictness addressStrictness() {
- return addressStrictness;
- }
+public record ConfigSpec(Vendor vendor, AddressStrictness addressStrictness, ServerType serverType,
+ InstanceType instanceType, boolean pluginMessaging, long unixTime) {
- public ServerType serverType() {
- return serverType;
+ public ConfigSpec {
+ Objects.requireNonNull(vendor, "vendor");
+ Objects.requireNonNull(addressStrictness, "addressStrictness");
+ Objects.requireNonNull(serverType, "serverType");
+ Objects.requireNonNull(instanceType, "instanceType");
}
- public Instant unixTime() {
+ public Instant unixTimestamp() {
return Instant.ofEpochSecond(unixTime);
}
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- ConfigSpec that = (ConfigSpec) o;
- return unixTime == that.unixTime && vendor == that.vendor
- && addressStrictness == that.addressStrictness && serverType == that.serverType;
- }
-
- @Override
- public int hashCode() {
- int result = vendor.hashCode();
- result = 31 * result + addressStrictness.hashCode();
- result = 31 * result + serverType.hashCode();
- result = 31 * result + (int) (unixTime ^ (unixTime >>> 32));
- return result;
- }
-
- @Override
- public String toString() {
- return "ConfigSpec{" +
- "vendor=" + vendor +
- ", addressStrictness=" + addressStrictness +
- ", serverType=" + serverType +
- ", unixTime=" + unixTime +
- '}';
- }
-
}
diff --git a/bans-core/src/test/java/space/arim/libertybans/it/ConfigSpecPossiblities.java b/bans-core/src/test/java/space/arim/libertybans/it/ConfigSpecPossiblities.java
index a87632e76..140d03f2c 100644
--- a/bans-core/src/test/java/space/arim/libertybans/it/ConfigSpecPossiblities.java
+++ b/bans-core/src/test/java/space/arim/libertybans/it/ConfigSpecPossiblities.java
@@ -1,6 +1,6 @@
/*
* LibertyBans
- * Copyright © 2021 Anand Beh
+ * Copyright © 2023 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
@@ -20,10 +20,12 @@
import space.arim.libertybans.core.database.Vendor;
import space.arim.libertybans.api.select.AddressStrictness;
+import space.arim.libertybans.core.env.InstanceType;
import space.arim.libertybans.core.uuid.ServerType;
import java.lang.reflect.AnnotatedElement;
import java.util.HashSet;
+import java.util.Objects;
import java.util.Set;
import java.util.stream.Stream;
@@ -32,22 +34,24 @@ class ConfigSpecPossiblities {
private final AnnotatedElement element;
ConfigSpecPossiblities(AnnotatedElement element) {
- this.element = element;
+ this.element = Objects.requireNonNull(element);
}
- private Stream getAllPossible(long time) {
+ private Stream getAllPossible(InstanceType instanceType, boolean pluginMessaging, long time) {
Set possibilities = new HashSet<>();
for (Vendor vendor : Vendor.values()) {
for (AddressStrictness addressStrictness : AddressStrictness.values()) {
for (ServerType serverType : ServerType.values()) {
- possibilities.add(new ConfigSpec(vendor, addressStrictness, serverType, time));
+ possibilities.add(new ConfigSpec(
+ vendor, addressStrictness, serverType, instanceType, pluginMessaging, time
+ ));
}
}
}
return possibilities.stream();
}
- private ConfigConstraints getConstraints() {
+ private ConfigConstraints getConstraints(PlatformSpecs platformSpecs) {
if (element.getAnnotation(NoDbAccess.class) != null) {
return new ConfigConstraints(
Set.of(Vendor.HSQLDB), Set.of(AddressStrictness.NORMAL), Set.of(ServerType.ONLINE));
@@ -64,15 +68,13 @@ private ConfigConstraints getConstraints() {
}
}
Set serverTypes;
- {
- SetServerType serverTypeConstraint = element.getAnnotation(SetServerType.class);
- if (serverTypeConstraint == null) {
- serverTypes = Set.of(ServerType.ONLINE);
- } else if (serverTypeConstraint.all()) {
- serverTypes = Set.of(ServerType.values());
- } else {
- serverTypes = Set.of(serverTypeConstraint.value());
- }
+ PlatformSpecs.ServerTypes serverTypeConstraint;
+ if (platformSpecs == null) {
+ serverTypes = Set.of(ServerType.ONLINE);
+ } else if ((serverTypeConstraint = platformSpecs.serverTypes()).all()) {
+ serverTypes = Set.of(ServerType.values());
+ } else {
+ serverTypes = Set.of(serverTypeConstraint.value());
}
Set vendors;
{
@@ -86,39 +88,38 @@ private ConfigConstraints getConstraints() {
return new ConfigConstraints(vendors, addressStrictnesses, serverTypes);
}
- private static class ConfigConstraints {
-
- private final Set strictnesses;
- private final Set vendors;
- private final Set serverTypes;
-
- ConfigConstraints(Set vendors, Set strictnesses, Set serverTypes) {
-
- this.vendors = vendors;
- this.strictnesses = strictnesses;
- this.serverTypes = serverTypes;
- }
+ private record ConfigConstraints(Set vendors, Set strictnesses,
+ Set serverTypes) {
boolean allows(ConfigSpec configSpec) {
- return vendors.contains(configSpec.vendor())
- && strictnesses.contains(configSpec.addressStrictness())
- && serverTypes.contains(configSpec.serverType());
+ return vendors.contains(configSpec.vendor())
+ && strictnesses.contains(configSpec.addressStrictness())
+ && serverTypes.contains(configSpec.serverType());
}
}
Stream getAll() {
- long defaultTime = SetTime.DEFAULT_TIME;
- if (element == null) {
- return getAllPossible(defaultTime);
- }
- long time = defaultTime;
+ long time;
SetTime setTime = element.getAnnotation(SetTime.class);
- if (setTime != null) {
+ if (setTime == null) {
+ time = SetTime.DEFAULT_TIME;
+ } else {
time = setTime.unixTime();
}
- Stream configurations = getAllPossible(time);
- ConfigConstraints constraints = getConstraints();
+ InstanceType instanceType;
+ boolean pluginMessaging;
+ PlatformSpecs platformSpecs = element.getAnnotation(PlatformSpecs.class);
+ if (platformSpecs == null) {
+ // Make sure these defaults match those in PlatformSpecs
+ instanceType = InstanceType.PROXY;
+ pluginMessaging = false;
+ } else {
+ instanceType = platformSpecs.instanceType();
+ pluginMessaging = platformSpecs.pluginMessaging();
+ }
+ Stream configurations = getAllPossible(instanceType, pluginMessaging, time);
+ ConfigConstraints constraints = getConstraints(platformSpecs);
return configurations.filter(constraints::allows);
}
diff --git a/bans-core/src/test/java/space/arim/libertybans/it/DatabaseInstance.java b/bans-core/src/test/java/space/arim/libertybans/it/DatabaseInstance.java
index 16599edca..caf9c3dd3 100644
--- a/bans-core/src/test/java/space/arim/libertybans/it/DatabaseInstance.java
+++ b/bans-core/src/test/java/space/arim/libertybans/it/DatabaseInstance.java
@@ -92,14 +92,13 @@ Optional createInfo() {
}
private void createDatabase(String database) {
- switch (this) {
- case MARIADB_RETRO, MARIADB_LEGACY, MARIADB_MODERN, MYSQL -> {
- createDatabaseUsing("jdbc:mariadb", database, " CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
- }
- case POSTGRES_LEGACY, POSTGRES_MODERN, COCKROACHDB -> {
- createDatabaseUsing("jdbc:postgresql", database, "");
- }
- default -> throw new IllegalStateException("No database creation exists");
+ switch (vendor) {
+ case MARIADB, MYSQL ->
+ createDatabaseUsing("jdbc:mariadb", database, " CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
+ case POSTGRES, COCKROACH ->
+ createDatabaseUsing("jdbc:postgresql", database, "");
+ default ->
+ throw new IllegalStateException("No database creation exists for " + this);
}
}
diff --git a/bans-core/src/test/java/space/arim/libertybans/it/InjectionInvocationContextProvider.java b/bans-core/src/test/java/space/arim/libertybans/it/InjectionInvocationContextProvider.java
index c6094e15f..28db6eb57 100644
--- a/bans-core/src/test/java/space/arim/libertybans/it/InjectionInvocationContextProvider.java
+++ b/bans-core/src/test/java/space/arim/libertybans/it/InjectionInvocationContextProvider.java
@@ -47,37 +47,28 @@ public Stream provideTestTemplateInvocationContex
boolean irrelevantData = context.getRequiredTestMethod().isAnnotationPresent(IrrelevantData.class);
ResourceCreator creator = new ResourceCreator(context.getRoot().getStore(NAMESPACE));
- return new ConfigSpecPossiblities(context.getElement().orElse(null))
+ return new ConfigSpecPossiblities(context.getElement().orElseThrow())
.getAll()
.flatMap((throwaway) ? creator::createIsolated : creator::create)
.map((injector) -> new InjectorInvocationContext(injector, throwaway, irrelevantData));
}
- private static class InjectorInvocationContext implements TestTemplateInvocationContext {
-
- private final Injector injector;
- private final boolean throwaway;
- private final boolean irrelevantData;
-
- InjectorInvocationContext(Injector injector, boolean throwaway, boolean irrelevantData) {
- this.injector = injector;
- this.throwaway = throwaway;
- this.irrelevantData = irrelevantData;
- }
+ private record InjectorInvocationContext(Injector injector, boolean throwaway,
+ boolean irrelevantData) implements TestTemplateInvocationContext {
@Override
- public List getAdditionalExtensions() {
- List extensions = new ArrayList<>(3);
- extensions.add(new InjectorParameterResolver(injector));
- if (!throwaway) {
- extensions.add(new InjectorCleanupCallback(injector));
- }
- if (irrelevantData) {
- extensions.add(new IrrelevantDataCallback(injector));
+ public List getAdditionalExtensions() {
+ List extensions = new ArrayList<>(3);
+ extensions.add(new InjectorParameterResolver(injector));
+ if (!throwaway) {
+ extensions.add(new InjectorCleanupCallback(injector));
+ }
+ if (irrelevantData) {
+ extensions.add(new IrrelevantDataCallback(injector));
+ }
+ return extensions;
}
- return extensions;
- }
- }
+ }
}
diff --git a/bans-core/src/test/java/space/arim/libertybans/it/InjectorCleanupCallback.java b/bans-core/src/test/java/space/arim/libertybans/it/InjectorCleanupCallback.java
index 39699850c..e223826db 100644
--- a/bans-core/src/test/java/space/arim/libertybans/it/InjectorCleanupCallback.java
+++ b/bans-core/src/test/java/space/arim/libertybans/it/InjectorCleanupCallback.java
@@ -1,6 +1,6 @@
/*
* LibertyBans
- * Copyright © 2021 Anand Beh
+ * Copyright © 2023 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
@@ -21,14 +21,11 @@
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
-import space.arim.injector.Identifier;
import space.arim.injector.Injector;
import space.arim.libertybans.core.database.InternalDatabase;
import space.arim.libertybans.core.punish.sync.SQLSynchronizationMessenger;
import space.arim.libertybans.core.service.SettableTime;
-import java.time.Instant;
-
final class InjectorCleanupCallback implements AfterEachCallback {
private final Injector injector;
@@ -42,8 +39,7 @@ public void afterEach(ExtensionContext context) throws Exception {
// Reset database
injector.request(InternalDatabase.class).truncateAllTables();
// Reset global clock
- Instant startTime = injector.request(Identifier.ofTypeAndNamed(Instant.class, "testStartTime"));
- injector.request(SettableTime.class).setTimestamp(startTime);
+ injector.request(SettableTime.class).reset();
// Reset synchronization
injector.request(SQLSynchronizationMessenger.class).resetLastTimestamp();
}
diff --git a/bans-core/src/test/java/space/arim/libertybans/it/PlatformSpecs.java b/bans-core/src/test/java/space/arim/libertybans/it/PlatformSpecs.java
new file mode 100644
index 000000000..2dd3c0868
--- /dev/null
+++ b/bans-core/src/test/java/space/arim/libertybans/it/PlatformSpecs.java
@@ -0,0 +1,65 @@
+/*
+ * LibertyBans
+ * Copyright © 2023 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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * LibertyBans 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with LibertyBans. If not, see
+ * and navigate to version 3 of the GNU Affero General Public License.
+ */
+
+package space.arim.libertybans.it;
+
+import space.arim.libertybans.core.env.InstanceType;
+import space.arim.libertybans.core.uuid.ServerType;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Details related to the platform implementation
+ *
+ */
+// Thankfully, annotations implement sane equals and hashCode
+@Retention(RUNTIME)
+@Target(METHOD)
+public @interface PlatformSpecs {
+
+ ServerTypes serverTypes() default @ServerTypes(value = {}, all = true);
+
+ // Make sure these defaults match those in ConfigSpecPossibilities
+
+ InstanceType instanceType() default InstanceType.PROXY;
+
+ boolean pluginMessaging() default false;
+
+ @interface ServerTypes {
+
+ /**
+ * Sets the server types
+ *
+ * @return the server types to test
+ */
+ ServerType[] value();
+
+ /**
+ * Whether to use all server types. Overrides the value
+ *
+ * @return true to use all types
+ */
+ boolean all() default false;
+
+ }
+}
diff --git a/bans-core/src/test/java/space/arim/libertybans/it/ResourceCreator.java b/bans-core/src/test/java/space/arim/libertybans/it/ResourceCreator.java
index eeb138ab9..2315db010 100644
--- a/bans-core/src/test/java/space/arim/libertybans/it/ResourceCreator.java
+++ b/bans-core/src/test/java/space/arim/libertybans/it/ResourceCreator.java
@@ -1,6 +1,6 @@
/*
* LibertyBans
- * Copyright © 2021 Anand Beh
+ * Copyright © 2023 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
@@ -29,12 +29,12 @@
import space.arim.libertybans.core.CommandsModule;
import space.arim.libertybans.core.PillarOneReplacementModule;
import space.arim.libertybans.core.PillarTwoBindModule;
+import space.arim.libertybans.core.env.InstanceType;
import space.arim.libertybans.it.env.QuackBindModule;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.time.Instant;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.stream.Stream;
@@ -79,11 +79,9 @@ private Optional createSingle(ConfigSpec configSpec, DatabaseInstance
Injector injector = new InjectorBuilder()
.bindInstance(Identifier.ofTypeAndNamed(Path.class, "folder"), tempDirectory)
+ .bindInstance(InstanceType.class, InstanceType.PROXY)
.bindInstance(ConfigSpec.class, configSpec)
.bindInstance(DatabaseInfo.class, databaseInfo)
- // The next two bindings are for ITs only
- .bindInstance(DatabaseInstance.class, database)
- .bindInstance(Identifier.ofTypeAndNamed(Instant.class, "testStartTime"), configSpec.unixTime())
.addBindModules(
new ApiBindModule(),
new PillarOneReplacementModule(),
diff --git a/bans-core/src/test/java/space/arim/libertybans/it/SetServerType.java b/bans-core/src/test/java/space/arim/libertybans/it/SetServerType.java
index 00914f735..76063031f 100644
--- a/bans-core/src/test/java/space/arim/libertybans/it/SetServerType.java
+++ b/bans-core/src/test/java/space/arim/libertybans/it/SetServerType.java
@@ -1,6 +1,6 @@
/*
* LibertyBans
- * Copyright © 2021 Anand Beh
+ * Copyright © 2023 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,18 +31,6 @@
@Target(METHOD)
public @interface SetServerType {
- /**
- * Sets the server types
- *
- * @return the server types to test
- */
- ServerType[] value() default {};
-
- /**
- * Whether to use all server types. Overrides {@code value}
- *
- * @return true to use all server types
- */
- boolean all() default false;
+ ServerType value();
}
diff --git a/bans-core/src/test/java/space/arim/libertybans/it/env/QuackBindModule.java b/bans-core/src/test/java/space/arim/libertybans/it/env/QuackBindModule.java
index 0bf548309..ee0a4532e 100644
--- a/bans-core/src/test/java/space/arim/libertybans/it/env/QuackBindModule.java
+++ b/bans-core/src/test/java/space/arim/libertybans/it/env/QuackBindModule.java
@@ -22,6 +22,7 @@
import jakarta.inject.Singleton;
import space.arim.api.env.PlatformHandle;
import space.arim.libertybans.core.env.EnvEnforcer;
+import space.arim.libertybans.core.env.EnvMessageChannel;
import space.arim.libertybans.core.env.EnvServerNameDetection;
import space.arim.libertybans.core.env.EnvUserResolver;
import space.arim.libertybans.core.env.Environment;
@@ -60,6 +61,10 @@ public EnvUserResolver resolver(QuackUserResolver resolver) {
return resolver;
}
+ public EnvMessageChannel> messageChannel(EnvMessageChannel.NoOp messageChannel) {
+ return messageChannel;
+ }
+
public EnvServerNameDetection serverNameDetection() {
return (scopeManager) -> {};
}
diff --git a/bans-core/src/test/java/space/arim/libertybans/it/env/QuackEnforcer.java b/bans-core/src/test/java/space/arim/libertybans/it/env/QuackEnforcer.java
index f5628024c..cd73c52c4 100644
--- a/bans-core/src/test/java/space/arim/libertybans/it/env/QuackEnforcer.java
+++ b/bans-core/src/test/java/space/arim/libertybans/it/env/QuackEnforcer.java
@@ -25,12 +25,15 @@
import space.arim.libertybans.core.config.InternalFormatter;
import space.arim.libertybans.core.env.AbstractEnvEnforcer;
import space.arim.libertybans.core.env.Interlocutor;
+import space.arim.libertybans.core.env.message.PluginMessage;
import space.arim.libertybans.it.env.platform.QuackPlatform;
import space.arim.libertybans.it.env.platform.QuackPlayer;
+import space.arim.libertybans.it.env.platform.ReceivedPluginMessage;
import space.arim.omnibus.util.concurrent.CentralisedFuture;
import space.arim.omnibus.util.concurrent.FactoryOfTheFuture;
import java.net.InetAddress;
+import java.util.Collection;
import java.util.UUID;
import java.util.function.Consumer;
@@ -46,8 +49,8 @@ public QuackEnforcer(FactoryOfTheFuture futuresFactory, InternalFormatter format
}
@Override
- protected CentralisedFuture doForAllPlayers(Consumer callback) {
- platform.getAllPlayers().forEach(callback);
+ public CentralisedFuture doForAllPlayers(Consumer> callback) {
+ callback.accept(platform.getAllPlayers());
return completedVoid();
}
@@ -62,6 +65,12 @@ public void kickPlayer(QuackPlayer player, Component message) {
player.kickPlayer(message);
}
+ @Override
+ public boolean sendPluginMessageIfListening(QuackPlayer player, PluginMessage pluginMessage, D data) {
+ player.receivedPluginMessages().add(new ReceivedPluginMessage<>(pluginMessage, data));
+ return true;
+ }
+
@Override
public UUID getUniqueIdFor(QuackPlayer player) {
return player.getUniqueId();
@@ -72,6 +81,11 @@ public InetAddress getAddressFor(QuackPlayer player) {
return player.getAddress();
}
+ @Override
+ public String getNameFor(QuackPlayer player) {
+ return player.getName();
+ }
+
@Override
public boolean hasPermission(QuackPlayer player, String permission) {
return player.hasPermission(permission);
diff --git a/bans-core/src/test/java/space/arim/libertybans/it/env/platform/PlatformSpecsEqualityTest.java b/bans-core/src/test/java/space/arim/libertybans/it/env/platform/PlatformSpecsEqualityTest.java
new file mode 100644
index 000000000..4df180017
--- /dev/null
+++ b/bans-core/src/test/java/space/arim/libertybans/it/env/platform/PlatformSpecsEqualityTest.java
@@ -0,0 +1,60 @@
+/*
+ * LibertyBans
+ * Copyright © 2023 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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * LibertyBans 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with LibertyBans. If not, see
+ * and navigate to version 3 of the GNU Affero General Public License.
+ */
+
+package space.arim.libertybans.it.env.platform;
+
+import org.junit.jupiter.api.Test;
+import space.arim.libertybans.core.env.InstanceType;
+import space.arim.libertybans.it.PlatformSpecs;
+
+import java.lang.reflect.Method;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+
+public class PlatformSpecsEqualityTest {
+
+ private boolean equalityFor(String otherMethod) throws NoSuchMethodException {
+ var thisClass = getClass();
+ Method firstMethod = thisClass.getDeclaredMethod("value1");
+ Method secondMethod = thisClass.getDeclaredMethod(otherMethod);
+ PlatformSpecs firstAnnotation = firstMethod.getAnnotation(PlatformSpecs.class);
+ PlatformSpecs secondAnnotation = secondMethod.getAnnotation(PlatformSpecs.class);
+ return firstAnnotation.equals(secondAnnotation);
+ }
+
+ @Test
+ public void isEqual() throws NoSuchMethodException {
+ assertFalse(equalityFor("value2"));
+ assertTrue(equalityFor("value3"));
+ assertFalse(equalityFor("value4"));
+ }
+
+ @PlatformSpecs(instanceType = InstanceType.PROXY, pluginMessaging = false)
+ void value1() {}
+ @PlatformSpecs(instanceType = InstanceType.GAME_SERVER)
+ void value2() {}
+ @PlatformSpecs(instanceType = InstanceType.PROXY, pluginMessaging = false)
+ void value3() {}
+ @PlatformSpecs(instanceType = InstanceType.PROXY, pluginMessaging = true)
+ void value4() {}
+
+}
diff --git a/bans-core/src/test/java/space/arim/libertybans/it/env/platform/QuackPlayer.java b/bans-core/src/test/java/space/arim/libertybans/it/env/platform/QuackPlayer.java
index e75d85323..35081b255 100644
--- a/bans-core/src/test/java/space/arim/libertybans/it/env/platform/QuackPlayer.java
+++ b/bans-core/src/test/java/space/arim/libertybans/it/env/platform/QuackPlayer.java
@@ -1,6 +1,6 @@
/*
* LibertyBans
- * Copyright © 2021 Anand Beh
+ * Copyright © 2023 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
@@ -28,6 +28,7 @@
import space.arim.omnibus.util.ThisClass;
import java.net.InetAddress;
+import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
@@ -39,6 +40,7 @@ public class QuackPlayer implements MessageOnlyAudience {
private final InetAddress address;
private final Set permissions;
+ private final Set> receivedPluginMessages = new HashSet<>();
private static final Logger logger = LoggerFactory.getLogger(ThisClass.get());
@@ -79,6 +81,10 @@ public void readdToPlatform() {
platform.addPlayer(this);
}
+ public Set> receivedPluginMessages() {
+ return receivedPluginMessages;
+ }
+
@Override
public void sendMessage(@NonNull Identity source, @NonNull Component message, @NonNull MessageType type) {
String displayMessage = platform.toDisplay(message);
diff --git a/bans-core/src/test/java/space/arim/libertybans/it/env/platform/ReceivedPluginMessage.java b/bans-core/src/test/java/space/arim/libertybans/it/env/platform/ReceivedPluginMessage.java
new file mode 100644
index 000000000..09b49a392
--- /dev/null
+++ b/bans-core/src/test/java/space/arim/libertybans/it/env/platform/ReceivedPluginMessage.java
@@ -0,0 +1,25 @@
+/*
+ * LibertyBans
+ * Copyright © 2023 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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * LibertyBans 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with LibertyBans. If not, see
+ * and navigate to version 3 of the GNU Affero General Public License.
+ */
+
+package space.arim.libertybans.it.env.platform;
+
+import space.arim.libertybans.core.env.message.PluginMessage;
+
+public record ReceivedPluginMessage(PluginMessage pluginMessage, D data) {
+}
diff --git a/bans-core/src/test/java/space/arim/libertybans/it/test/database/DatabaseRequirementsIT.java b/bans-core/src/test/java/space/arim/libertybans/it/test/database/DatabaseRequirementsIT.java
index 941cc12d9..2e2d9e7fb 100644
--- a/bans-core/src/test/java/space/arim/libertybans/it/test/database/DatabaseRequirementsIT.java
+++ b/bans-core/src/test/java/space/arim/libertybans/it/test/database/DatabaseRequirementsIT.java
@@ -23,8 +23,8 @@
import org.junit.jupiter.api.extension.ExtendWith;
import space.arim.libertybans.core.database.DatabaseManager;
import space.arim.libertybans.core.database.DatabaseRequirements;
+import space.arim.libertybans.core.database.InternalDatabase;
import space.arim.libertybans.core.database.Vendor;
-import space.arim.libertybans.it.DatabaseInstance;
import space.arim.libertybans.it.InjectionInvocationContextProvider;
import java.sql.Connection;
@@ -36,10 +36,10 @@
public class DatabaseRequirementsIT {
@TestTemplate
- public void databaseVersion(DatabaseManager databaseManager,
- DatabaseInstance databaseInstance) throws SQLException {
- Vendor vendor = databaseInstance.getVendor();
- try (Connection connection = databaseManager.getInternal().getConnection()) {
+ public void databaseVersion(DatabaseManager databaseManager) throws SQLException {
+ InternalDatabase database = databaseManager.getInternal();
+ Vendor vendor = database.getVendor();
+ try (Connection connection = database.getConnection()) {
assertDoesNotThrow(
new DatabaseRequirements(vendor, connection)::checkRequirementsAndYieldRetroSupport);
}
diff --git a/bans-core/src/test/java/space/arim/libertybans/it/test/importing/AdvancedBanImportIT.java b/bans-core/src/test/java/space/arim/libertybans/it/test/importing/AdvancedBanImportIT.java
index e480d619f..35caaf55f 100644
--- a/bans-core/src/test/java/space/arim/libertybans/it/test/importing/AdvancedBanImportIT.java
+++ b/bans-core/src/test/java/space/arim/libertybans/it/test/importing/AdvancedBanImportIT.java
@@ -35,6 +35,7 @@
import space.arim.libertybans.core.uuid.UUIDManager;
import space.arim.libertybans.it.DontInject;
import space.arim.libertybans.it.InjectionInvocationContextProvider;
+import space.arim.libertybans.it.PlatformSpecs;
import space.arim.libertybans.it.SetServerType;
import space.arim.libertybans.it.SetTime;
import space.arim.omnibus.util.UUIDUtil;
@@ -82,14 +83,14 @@ private void importFrom(String dataFile, ImportStatistics expectedStatistics) {
@TestTemplate
@SetTime(unixTime = SetTime.DEFAULT_TIME)
- @SetServerType(ServerType.OFFLINE)
+ @PlatformSpecs(serverTypes = @PlatformSpecs.ServerTypes(ServerType.OFFLINE))
public void sampleOneOffline() {
importFrom("sample-one-offline", new ImportStatistics(103, 332, 768));
}
@TestTemplate
@SetTime(unixTime = SetTime.DEFAULT_TIME)
- @SetServerType(ServerType.ONLINE)
+ @PlatformSpecs(serverTypes = @PlatformSpecs.ServerTypes(ServerType.ONLINE))
public void sampleTwoOnline() {
addToCache("ed5f12cd600745d9a4b9940524ddaecf", "A248", "Aerodactyl_");
addToCache("840d1667a0e24934a3bd1a7ebbbc0732", "Cxleos");
diff --git a/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/BungeeBindModule.java b/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/BungeeBindModule.java
index 0d26785ab..0dc2b0a33 100644
--- a/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/BungeeBindModule.java
+++ b/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/BungeeBindModule.java
@@ -28,6 +28,7 @@
import space.arim.api.env.bungee.BungeePlatformHandle;
import space.arim.api.env.PlatformHandle;
import space.arim.libertybans.core.env.EnvEnforcer;
+import space.arim.libertybans.core.env.EnvMessageChannel;
import space.arim.libertybans.core.env.EnvServerNameDetection;
import space.arim.libertybans.core.env.EnvUserResolver;
import space.arim.libertybans.core.env.Environment;
@@ -62,6 +63,10 @@ public EnvUserResolver resolver(BungeeUserResolver resolver) {
return resolver;
}
+ public EnvMessageChannel> messageChannel(BungeeMessageChannel messageChannel) {
+ return messageChannel;
+ }
+
public AddressReporter reporter(StandardAddressReporter reporter) {
return reporter;
}
diff --git a/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/BungeeEnforcer.java b/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/BungeeEnforcer.java
index d5767945e..24630a587 100644
--- a/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/BungeeEnforcer.java
+++ b/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/BungeeEnforcer.java
@@ -31,10 +31,12 @@
import space.arim.libertybans.core.config.InternalFormatter;
import space.arim.libertybans.core.env.AbstractEnvEnforcer;
import space.arim.libertybans.core.env.Interlocutor;
+import space.arim.libertybans.core.env.message.PluginMessage;
import space.arim.omnibus.util.concurrent.CentralisedFuture;
import space.arim.omnibus.util.concurrent.FactoryOfTheFuture;
import java.net.InetAddress;
+import java.util.Collection;
import java.util.UUID;
import java.util.function.Consumer;
@@ -43,19 +45,21 @@ public class BungeeEnforcer extends AbstractEnvEnforcer {
private final ProxyServer server;
private final AddressReporter addressReporter;
+ private final BungeeMessageChannel messageChannel;
@Inject
public BungeeEnforcer(FactoryOfTheFuture futuresFactory, InternalFormatter formatter,
Interlocutor interlocutor, AudienceRepresenter audienceRepresenter,
- ProxyServer server, AddressReporter addressReporter) {
+ ProxyServer server, AddressReporter addressReporter, BungeeMessageChannel messageChannel) {
super(futuresFactory, formatter, interlocutor, audienceRepresenter);
this.server = server;
this.addressReporter = addressReporter;
+ this.messageChannel = messageChannel;
}
@Override
- protected CentralisedFuture doForAllPlayers(Consumer callback) {
- server.getPlayers().forEach(callback);
+ public CentralisedFuture doForAllPlayers(Consumer> callback) {
+ callback.accept(server.getPlayers());
return completedVoid();
}
@@ -74,6 +78,12 @@ public void kickPlayer(ProxiedPlayer player, Component message) {
LegacyComponentSerializer.legacySection().serialize(message)));
}
+ @Override
+ public boolean sendPluginMessageIfListening(ProxiedPlayer player, PluginMessage pluginMessage, D data) {
+ messageChannel.sendPluginMessage(player, pluginMessage, data);
+ return true;
+ }
+
@Override
public UUID getUniqueIdFor(ProxiedPlayer player) {
return player.getUniqueId();
@@ -84,6 +94,11 @@ public InetAddress getAddressFor(ProxiedPlayer player) {
return addressReporter.getAddress(player);
}
+ @Override
+ public String getNameFor(ProxiedPlayer player) {
+ return player.getName();
+ }
+
@Override
public boolean hasPermission(ProxiedPlayer player, String permission) {
return player.hasPermission(permission);
diff --git a/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/BungeeLauncher.java b/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/BungeeLauncher.java
index b5876be44..001caac59 100644
--- a/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/BungeeLauncher.java
+++ b/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/BungeeLauncher.java
@@ -1,6 +1,6 @@
/*
* LibertyBans
- * Copyright © 2022 Anand Beh
+ * Copyright © 2023 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
@@ -35,6 +35,7 @@
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.plugin.Plugin;
import space.arim.libertybans.core.addon.AddonLoader;
+import space.arim.libertybans.core.env.InstanceType;
import space.arim.omnibus.Omnibus;
import space.arim.omnibus.OmnibusProvider;
@@ -60,6 +61,7 @@ public BaseFoundation launch() {
.bindInstance(Plugin.class, plugin)
.bindInstance(ProxyServer.class, plugin.getProxy())
.bindInstance(Identifier.ofTypeAndNamed(Path.class, "folder"), folder)
+ .bindInstance(InstanceType.class, InstanceType.PROXY)
.bindInstance(Omnibus.class, omnibus)
.addBindModules(
new ApiBindModule(),
diff --git a/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/BungeeMessageChannel.java b/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/BungeeMessageChannel.java
new file mode 100644
index 000000000..16d99f6f6
--- /dev/null
+++ b/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/BungeeMessageChannel.java
@@ -0,0 +1,81 @@
+/*
+ * LibertyBans
+ * Copyright © 2023 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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * LibertyBans 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with LibertyBans. If not, see
+ * and navigate to version 3 of the GNU Affero General Public License.
+ */
+
+package space.arim.libertybans.env.bungee;
+
+import jakarta.inject.Inject;
+import net.md_5.bungee.api.connection.ProxiedPlayer;
+import net.md_5.bungee.api.connection.Server;
+import net.md_5.bungee.api.event.PluginMessageEvent;
+import net.md_5.bungee.api.plugin.Listener;
+import net.md_5.bungee.api.plugin.Plugin;
+import net.md_5.bungee.event.EventHandler;
+import space.arim.libertybans.core.env.EnvMessageChannel;
+import space.arim.libertybans.core.env.PluginMessageAsBytes;
+import space.arim.libertybans.core.env.message.PluginMessage;
+
+import java.util.function.Consumer;
+
+public final class BungeeMessageChannel implements EnvMessageChannel {
+
+ private final Plugin plugin;
+
+ private static final String BUNGEE_CHANNEL = "BungeeCord";
+
+ @Inject
+ public BungeeMessageChannel(Plugin plugin) {
+ this.plugin = plugin;
+ }
+
+ void sendPluginMessage(ProxiedPlayer player, PluginMessage pluginMessage, D data) {
+ Server server = player.getServer();
+ if (server != null) {
+ server.sendData(BUNGEE_CHANNEL, new PluginMessageAsBytes<>(pluginMessage).generateBytes(data));
+ }
+ }
+
+ @Override
+ public void installHandler(Listener handler) {
+ plugin.getProxy().getPluginManager().registerListener(plugin, handler);
+ }
+
+ @Override
+ public void uninstallHandler(Listener handler) {
+ plugin.getProxy().getPluginManager().unregisterListener(handler);
+ }
+
+ @Override
+ public Listener createHandler(Consumer acceptor, PluginMessage, R> pluginMessage) {
+ return new Handler<>(acceptor, pluginMessage);
+ }
+
+ // Public for reflection purposes
+ public record Handler(Consumer acceptor, PluginMessage, R> pluginMessage) implements Listener {
+
+ @EventHandler
+ public void onReceive(PluginMessageEvent event) {
+ if (event.getSender() instanceof Server && event.getTag().equals(BUNGEE_CHANNEL)) {
+ new PluginMessageAsBytes<>(pluginMessage)
+ .readBytes(event.getData())
+ .ifPresent(acceptor);
+ }
+ }
+ }
+
+}
diff --git a/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/PluginMessagingListener.java b/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/PluginMessagingListener.java
deleted file mode 100644
index 477ec2742..000000000
--- a/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/PluginMessagingListener.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * LibertyBans
- * Copyright © 2023 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
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * LibertyBans 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with LibertyBans. If not, see
- * and navigate to version 3 of the GNU Affero General Public License.
- */
-
-package space.arim.libertybans.env.spigot;
-
-import jakarta.inject.Inject;
-import org.bukkit.Server;
-import org.bukkit.entity.Player;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.EventPriority;
-import org.bukkit.event.HandlerList;
-import org.bukkit.event.Listener;
-import org.bukkit.event.player.PlayerJoinEvent;
-import org.bukkit.plugin.Plugin;
-import org.bukkit.plugin.messaging.Messenger;
-import org.bukkit.plugin.messaging.PluginMessageListener;
-import space.arim.libertybans.core.env.PlatformListener;
-import space.arim.libertybans.core.env.message.GetServer;
-import space.arim.libertybans.core.scope.InternalScopeManager;
-
-public final class PluginMessagingListener implements PlatformListener, Listener, PluginMessageListener {
-
- private final Plugin plugin;
- private final InternalScopeManager scopeManager;
-
- private final PluginMessageData getServer = new PluginMessageData<>(new GetServer());
-
- static final String BUNGEE_CHANNEL = "BungeeCord";
-
- @Inject
- public PluginMessagingListener(Plugin plugin, InternalScopeManager scopeManager) {
- this.plugin = plugin;
- this.scopeManager = scopeManager;
- }
-
- @Override
- public void register() {
- Server server = plugin.getServer();
- server.getPluginManager().registerEvents(this, plugin);
- Messenger messenger = server.getMessenger();
- messenger.registerOutgoingPluginChannel(plugin, BUNGEE_CHANNEL);
- messenger.registerIncomingPluginChannel(plugin, BUNGEE_CHANNEL, this);
-
- // In case of '/libertybans restart', re-detect server name
- if (scopeManager.shouldDetectServerName()) {
- // Pick at most 4 online players just in case some of them quit
- plugin.getServer().getOnlinePlayers().stream().limit(4).forEach((player) -> {
- player.sendPluginMessage(
- plugin, BUNGEE_CHANNEL, getServer.generateBytes(null)
- );
- });
- }
- }
-
- @Override
- public void unregister() {
- HandlerList.unregisterAll(this);
- Messenger messenger = plugin.getServer().getMessenger();
- messenger.unregisterOutgoingPluginChannel(plugin, BUNGEE_CHANNEL);
- messenger.unregisterIncomingPluginChannel(plugin, BUNGEE_CHANNEL, this);
- }
-
- @EventHandler(priority = EventPriority.LOW)
- public void onJoin(PlayerJoinEvent event) {
- if (scopeManager.shouldDetectServerName()) {
- event.getPlayer().sendPluginMessage(
- plugin, BUNGEE_CHANNEL, getServer.generateBytes(null)
- );
- }
- }
-
- @Override
- public void onPluginMessageReceived(String channel, Player player, byte[] message) {
- if (channel.equals(BUNGEE_CHANNEL)) {
- getServer.readBytes(message)
- .map(GetServer.Response::server)
- .ifPresent(scopeManager::detectServerName);
- }
- }
-}
diff --git a/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/ServerNameListener.java b/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/ServerNameListener.java
new file mode 100644
index 000000000..57c73e0e6
--- /dev/null
+++ b/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/ServerNameListener.java
@@ -0,0 +1,63 @@
+/*
+ * LibertyBans
+ * Copyright © 2023 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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * LibertyBans 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with LibertyBans. If not, see
+ * and navigate to version 3 of the GNU Affero General Public License.
+ */
+
+package space.arim.libertybans.env.spigot;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.plugin.Plugin;
+import space.arim.libertybans.core.env.PlatformListener;
+import space.arim.libertybans.core.scope.ServerNameListenerBase;
+
+@Singleton
+public final class ServerNameListener implements PlatformListener, Listener {
+
+ private final Plugin plugin;
+ private final ServerNameListenerBase baseImpl;
+
+ @Inject
+ public ServerNameListener(Plugin plugin, ServerNameListenerBase baseImpl) {
+ this.plugin = plugin;
+ this.baseImpl = baseImpl;
+ }
+
+ @Override
+ public void register() {
+ baseImpl.register();
+ plugin.getServer().getPluginManager().registerEvents(this, plugin);
+ }
+
+ @Override
+ public void unregister() {
+ HandlerList.unregisterAll(this);
+ baseImpl.unregister();
+ }
+
+ @EventHandler(priority = EventPriority.LOW)
+ public void onJoin(PlayerJoinEvent event) {
+ baseImpl.onJoin(event.getPlayer());
+ }
+
+}
diff --git a/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/SpigotBindModule.java b/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/SpigotBindModule.java
index 1f58e8075..11c147eb5 100644
--- a/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/SpigotBindModule.java
+++ b/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/SpigotBindModule.java
@@ -27,6 +27,7 @@
import space.arim.api.env.bukkit.BukkitAudienceRepresenter;
import space.arim.api.env.bukkit.BukkitPlatformHandle;
import space.arim.libertybans.core.env.EnvEnforcer;
+import space.arim.libertybans.core.env.EnvMessageChannel;
import space.arim.libertybans.core.env.EnvServerNameDetection;
import space.arim.libertybans.core.env.EnvUserResolver;
import space.arim.libertybans.core.env.Environment;
@@ -63,6 +64,10 @@ public EnvUserResolver resolver(SpigotUserResolver resolver) {
return resolver;
}
+ public EnvMessageChannel> messageChannel(SpigotMessageChannel messageChannel) {
+ return messageChannel;
+ }
+
@Singleton
public CommandMapHelper commandMapHelper(SimpleCommandMapHelper scmh) {
return new CachingCommandMapHelper(scmh);
diff --git a/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/SpigotEnforcer.java b/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/SpigotEnforcer.java
index 6b09b535e..934fef5e8 100644
--- a/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/SpigotEnforcer.java
+++ b/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/SpigotEnforcer.java
@@ -25,36 +25,36 @@
import org.bukkit.Server;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
-import org.slf4j.LoggerFactory;
import space.arim.api.env.AudienceRepresenter;
-import space.arim.libertybans.core.config.Configs;
import space.arim.libertybans.core.config.InternalFormatter;
import space.arim.libertybans.core.env.AbstractEnvEnforcer;
import space.arim.libertybans.core.env.Interlocutor;
-import space.arim.libertybans.core.env.message.KickPlayer;
+import space.arim.libertybans.core.env.message.PluginMessage;
import space.arim.morepaperlib.adventure.MorePaperLibAdventure;
import space.arim.omnibus.util.concurrent.CentralisedFuture;
import space.arim.omnibus.util.concurrent.FactoryOfTheFuture;
import java.net.InetAddress;
+import java.util.Collection;
import java.util.UUID;
import java.util.function.Consumer;
@Singleton
public class SpigotEnforcer extends AbstractEnvEnforcer {
- private final Configs configs;
private final Server server;
private final MorePaperLibAdventure morePaperLibAdventure;
+ private final SpigotMessageChannel messageChannel;
@Inject
public SpigotEnforcer(FactoryOfTheFuture futuresFactory, InternalFormatter formatter,
Interlocutor interlocutor, AudienceRepresenter audienceRepresenter,
- Configs configs, Server server, MorePaperLibAdventure morePaperLibAdventure) {
+ Server server, MorePaperLibAdventure morePaperLibAdventure,
+ SpigotMessageChannel messageChannel) {
super(futuresFactory, formatter, interlocutor, audienceRepresenter);
- this.configs = configs;
this.server = server;
this.morePaperLibAdventure = morePaperLibAdventure;
+ this.messageChannel = messageChannel;
}
@SuppressWarnings("unchecked")
@@ -64,37 +64,24 @@ private CentralisedFuture runSync(Runnable command) {
}
@Override
- protected CentralisedFuture doForAllPlayers(Consumer callback) {
+ public CentralisedFuture doForAllPlayers(Consumer> callback) {
if (morePaperLibAdventure.getMorePaperLib().scheduling().isUsingFolia()) {
- server.getOnlinePlayers().forEach(callback);
+ callback.accept(server.getOnlinePlayers());
return completedVoid();
}
- return runSync(() -> server.getOnlinePlayers().forEach(callback));
+ return runSync(() -> callback.accept(server.getOnlinePlayers()));
}
@Override
public void kickPlayer(Player player, Component message) {
- if (configs.getMainConfig().platforms().gameServers().kickViaPluginMessaging()) {
-
- if (player.getListeningPluginChannels().contains(PluginMessagingListener.BUNGEE_CHANNEL)) {
- byte[] kickPlayerData = new PluginMessageData<>(new KickPlayer())
- .generateBytes(new KickPlayer.Data(
- player.getName(), message
- ));
- player.sendPluginMessage(
- morePaperLibAdventure.getMorePaperLib().getPlugin(),
- PluginMessagingListener.BUNGEE_CHANNEL,
- kickPlayerData
- );
- return;
- }
- LoggerFactory.getLogger(getClass()).warn(
- "Kicking via plugin messaging is enabled, but the proper channel is not listened on."
- );
- }
morePaperLibAdventure.kickPlayer(player, message);
}
+ @Override
+ public boolean sendPluginMessageIfListening(Player player, PluginMessage pluginMessage, D data) {
+ return messageChannel.sendPluginMessage(player, pluginMessage, data);
+ }
+
@Override
public CentralisedFuture doForPlayerIfOnline(UUID uuid, Consumer callback) {
if (morePaperLibAdventure.getMorePaperLib().scheduling().isUsingFolia()) {
@@ -122,6 +109,11 @@ public InetAddress getAddressFor(Player player) {
return player.getAddress().getAddress();
}
+ @Override
+ public String getNameFor(Player player) {
+ return player.getName();
+ }
+
@Override
public boolean hasPermission(Player player, String permission) {
return player.hasPermission(permission);
diff --git a/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/SpigotEnv.java b/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/SpigotEnv.java
index 577d830c6..d2e711cb1 100644
--- a/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/SpigotEnv.java
+++ b/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/SpigotEnv.java
@@ -31,15 +31,18 @@ public final class SpigotEnv implements Environment {
private final Provider connectionListener;
private final Provider chatListener;
- private final Provider messagingListener;
+ private final Provider serverNameListener;
+ private final Provider pluginMessageChannel;
private final CommandHandler.CommandHelper commandHelper;
@Inject
public SpigotEnv(Provider connectionListener, Provider chatListener,
- Provider messagingListener, CommandHandler.CommandHelper commandHelper) {
+ Provider serverNameListener, Provider pluginMessageChannel,
+ CommandHandler.CommandHelper commandHelper) {
this.connectionListener = connectionListener;
this.chatListener = chatListener;
- this.messagingListener = messagingListener;
+ this.serverNameListener = serverNameListener;
+ this.pluginMessageChannel = pluginMessageChannel;
this.commandHelper = commandHelper;
}
@@ -48,7 +51,8 @@ public Set createListeners() {
return Set.of(
connectionListener.get(),
chatListener.get(),
- messagingListener.get(),
+ serverNameListener.get(),
+ pluginMessageChannel.get(),
new CommandHandler(commandHelper, Commands.BASE_COMMAND_NAME, false)
);
}
diff --git a/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/SpigotLauncher.java b/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/SpigotLauncher.java
index cd35eb5f3..5c20192b5 100644
--- a/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/SpigotLauncher.java
+++ b/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/SpigotLauncher.java
@@ -1,6 +1,6 @@
/*
* LibertyBans
- * Copyright © 2022 Anand Beh
+ * Copyright © 2023 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
@@ -36,6 +36,7 @@
import org.bukkit.Server;
import org.bukkit.plugin.java.JavaPlugin;
import space.arim.libertybans.core.addon.AddonLoader;
+import space.arim.libertybans.core.env.InstanceType;
import space.arim.omnibus.Omnibus;
import space.arim.omnibus.OmnibusProvider;
@@ -62,6 +63,7 @@ public BaseFoundation launch() {
.bindInstance(Plugin.class, plugin)
.bindInstance(Server.class, plugin.getServer())
.bindInstance(Identifier.ofTypeAndNamed(Path.class, "folder"), folder)
+ .bindInstance(InstanceType.class, InstanceType.GAME_SERVER)
.bindInstance(Omnibus.class, omnibus)
.addBindModules(
new ApiBindModule(),
diff --git a/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/SpigotMessageChannel.java b/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/SpigotMessageChannel.java
new file mode 100644
index 000000000..883286fa3
--- /dev/null
+++ b/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/SpigotMessageChannel.java
@@ -0,0 +1,92 @@
+/*
+ * LibertyBans
+ * Copyright © 2023 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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * LibertyBans 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with LibertyBans. If not, see
+ * and navigate to version 3 of the GNU Affero General Public License.
+ */
+
+package space.arim.libertybans.env.spigot;
+
+import jakarta.inject.Inject;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.plugin.messaging.PluginMessageListener;
+import space.arim.libertybans.core.env.EnvMessageChannel;
+import space.arim.libertybans.core.env.PlatformListener;
+import space.arim.libertybans.core.env.PluginMessageAsBytes;
+import space.arim.libertybans.core.env.message.PluginMessage;
+
+import java.util.function.Consumer;
+
+public final class SpigotMessageChannel implements PlatformListener, EnvMessageChannel {
+
+ private final Plugin plugin;
+
+ static final String BUNGEE_CHANNEL = "BungeeCord";
+
+ @Inject
+ public SpigotMessageChannel(Plugin plugin) {
+ this.plugin = plugin;
+ }
+
+ @Override
+ public void register() {
+ plugin.getServer().getMessenger().registerOutgoingPluginChannel(plugin, BUNGEE_CHANNEL);
+ }
+
+ @Override
+ public void unregister() {
+ plugin.getServer().getMessenger().unregisterOutgoingPluginChannel(plugin, BUNGEE_CHANNEL);
+ }
+
+ boolean sendPluginMessage(Player player, PluginMessage pluginMessage, D data) {
+ boolean listened = player.getListeningPluginChannels().contains(BUNGEE_CHANNEL);
+ if (listened) {
+ player.sendPluginMessage(
+ plugin, BUNGEE_CHANNEL,
+ new PluginMessageAsBytes<>(pluginMessage).generateBytes(data)
+ );
+ }
+ return listened;
+ }
+
+ @Override
+ public void installHandler(PluginMessageListener handler) {
+ plugin.getServer().getMessenger().registerIncomingPluginChannel(plugin, BUNGEE_CHANNEL, handler);
+ }
+
+ @Override
+ public void uninstallHandler(PluginMessageListener handler) {
+ plugin.getServer().getMessenger().unregisterIncomingPluginChannel(plugin, BUNGEE_CHANNEL, handler);
+ }
+
+ @Override
+ public PluginMessageListener createHandler(Consumer acceptor, PluginMessage, R> pluginMessage) {
+ return new Handler<>(acceptor, pluginMessage);
+ }
+
+ record Handler(Consumer acceptor, PluginMessage, R> pluginMessage) implements PluginMessageListener {
+
+ @Override
+ public void onPluginMessageReceived(String channel, Player player, byte[] message) {
+ if (channel.equals(BUNGEE_CHANNEL)) {
+ new PluginMessageAsBytes<>(pluginMessage)
+ .readBytes(message)
+ .ifPresent(acceptor);
+ }
+ }
+ }
+
+}
diff --git a/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/PluginMessageData.java b/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/PluginMessageData.java
deleted file mode 100644
index 35750affe..000000000
--- a/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/PluginMessageData.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * LibertyBans
- * Copyright © 2023 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
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * LibertyBans 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with LibertyBans. If not, see
- * and navigate to version 3 of the GNU Affero General Public License.
- */
-
-package space.arim.libertybans.env.sponge;
-
-import org.spongepowered.api.network.channel.ChannelBuf;
-import space.arim.libertybans.core.env.message.PluginMessage;
-import space.arim.libertybans.core.env.message.PluginMessageInput;
-import space.arim.libertybans.core.env.message.PluginMessageOutput;
-
-import java.io.IOException;
-import java.util.Optional;
-
-record PluginMessageData(PluginMessage pluginMessage) {
-
- void writeBuffer(D data, ChannelBuf buffer) {
- pluginMessage.writeTo(data, new ChannelBufAsOutput(buffer));
- }
-
- Optional readBuffer(ChannelBuf buffer) {
- return pluginMessage.readFrom(new ChannelBufAsInput(buffer));
- }
-
- record ChannelBufAsOutput(ChannelBuf buffer) implements PluginMessageOutput {
- @Override
- public void writeUTF(String utf) throws IOException {
- buffer.writeUTF(utf);
- }
- }
-
- record ChannelBufAsInput(ChannelBuf buffer) implements PluginMessageInput {
- @Override
- public String readUTF() throws IOException {
- return buffer.readUTF();
- }
- }
-}
diff --git a/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/PluginMessagingListener.java b/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/PluginMessagingListener.java
deleted file mode 100644
index 815be1dde..000000000
--- a/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/PluginMessagingListener.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * LibertyBans
- * Copyright © 2023 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
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * LibertyBans 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with LibertyBans. If not, see
- * and navigate to version 3 of the GNU Affero General Public License.
- */
-
-package space.arim.libertybans.env.sponge;
-
-import jakarta.inject.Inject;
-import org.slf4j.LoggerFactory;
-import org.spongepowered.api.Game;
-import org.spongepowered.api.ResourceKey;
-import org.spongepowered.api.entity.living.player.server.ServerPlayer;
-import org.spongepowered.api.event.Listener;
-import org.spongepowered.api.event.Order;
-import org.spongepowered.api.event.network.ServerSideConnectionEvent;
-import org.spongepowered.api.network.EngineConnectionSide;
-import org.spongepowered.api.network.ServerSideConnection;
-import org.spongepowered.api.network.channel.ChannelBuf;
-import org.spongepowered.api.network.channel.raw.RawDataChannel;
-import org.spongepowered.api.network.channel.raw.play.RawPlayDataChannel;
-import org.spongepowered.api.network.channel.raw.play.RawPlayDataHandler;
-import space.arim.libertybans.core.env.PlatformListener;
-import space.arim.libertybans.core.env.message.GetServer;
-import space.arim.libertybans.core.env.message.PluginMessage;
-import space.arim.libertybans.core.scope.InternalScopeManager;
-import space.arim.libertybans.env.sponge.listener.RegisterListeners;
-
-import java.util.Optional;
-
-public final class PluginMessagingListener implements PlatformListener, RawPlayDataHandler {
-
- private final RegisterListeners registerListeners;
- private final Game game;
- private final InternalScopeManager scopeManager;
-
- @Inject
- public PluginMessagingListener(RegisterListeners registerListeners, Game game, InternalScopeManager scopeManager) {
- this.registerListeners = registerListeners;
- this.game = game;
- this.scopeManager = scopeManager;
- }
-
- static Optional findChannel(Game game) {
- return game.channelManager()
- .get(ResourceKey.of("bungeecord", "main"))
- .flatMap((channel) -> {
- if (channel instanceof RawDataChannel rawDataChannel) {
- return Optional.of(rawDataChannel.play());
- } else {
- return Optional.empty();
- }
- });
- }
-
- static void sendPluginMessage(RawPlayDataChannel channel, ServerPlayer player,
- PluginMessage pluginMessage, D data) {
- channel.sendTo(player, (buffer) -> {
- new PluginMessageData<>(pluginMessage).writeBuffer(data, buffer);
- }).exceptionally((ex) -> {
- LoggerFactory.getLogger(PluginMessagingListener.class).error("Failed to send plugin message", ex);
- return null;
- });
- }
-
- @Override
- public void register() {
- registerListeners.register(this);
- findChannel(game).ifPresent((channel) -> {
- channel.addHandler(EngineConnectionSide.SERVER, this);
-
- // In case of '/libertybans restart', re-detect server name
- if (scopeManager.shouldDetectServerName()) {
- // Pick at most 4 online players just in case some of them quit
- game.server().onlinePlayers().stream().limit(4).forEach((player) -> {
- sendPluginMessage(channel, player, new GetServer(), null);
- });
- }
- });
- }
-
- @Override
- public void unregister() {
- registerListeners.unregister(this);
- findChannel(game)
- .ifPresent((channel) -> channel.removeHandler(this));
- }
-
- @Listener(order = Order.EARLY)
- public void onJoin(ServerSideConnectionEvent.Join event) {
- if (scopeManager.shouldDetectServerName()) {
- findChannel(game).ifPresent((channel) -> {
- sendPluginMessage(channel, event.player(), new GetServer(), null);
- });
- }
- }
-
- @Override
- public void handlePayload(ChannelBuf data, ServerSideConnection connection) {
- new PluginMessageData<>(new GetServer())
- .readBuffer(data)
- .map(GetServer.Response::server)
- .ifPresent(scopeManager::detectServerName);
- }
-}
diff --git a/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/ServerNameListener.java b/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/ServerNameListener.java
new file mode 100644
index 000000000..5ad4f4b9c
--- /dev/null
+++ b/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/ServerNameListener.java
@@ -0,0 +1,61 @@
+/*
+ * LibertyBans
+ * Copyright © 2023 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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * LibertyBans 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with LibertyBans. If not, see
+ * and navigate to version 3 of the GNU Affero General Public License.
+ */
+
+package space.arim.libertybans.env.sponge;
+
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import org.spongepowered.api.entity.living.player.server.ServerPlayer;
+import org.spongepowered.api.event.Listener;
+import org.spongepowered.api.event.Order;
+import org.spongepowered.api.event.network.ServerSideConnectionEvent;
+import space.arim.libertybans.core.env.PlatformListener;
+import space.arim.libertybans.core.scope.ServerNameListenerBase;
+import space.arim.libertybans.env.sponge.listener.RegisterListeners;
+
+@Singleton
+public final class ServerNameListener implements PlatformListener {
+
+ private final RegisterListeners registerListeners;
+ private final ServerNameListenerBase baseImpl;
+
+ @Inject
+ public ServerNameListener(RegisterListeners registerListeners, ServerNameListenerBase baseImpl) {
+ this.registerListeners = registerListeners;
+ this.baseImpl = baseImpl;
+ }
+
+ @Override
+ public void register() {
+ baseImpl.register();
+ registerListeners.register(this);
+ }
+
+ @Override
+ public void unregister() {
+ registerListeners.unregister(this);
+ baseImpl.unregister();
+ }
+
+ @Listener(order = Order.EARLY)
+ public void onJoin(ServerSideConnectionEvent.Join event) {
+ baseImpl.onJoin(event.player());
+ }
+
+}
diff --git a/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/SpongeBindModule.java b/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/SpongeBindModule.java
index 872479ec5..150def4f7 100644
--- a/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/SpongeBindModule.java
+++ b/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/SpongeBindModule.java
@@ -28,6 +28,7 @@
import space.arim.api.env.sponge.SpongeAudienceRepresenter;
import space.arim.api.env.sponge.SpongePlatformHandle;
import space.arim.libertybans.core.env.EnvEnforcer;
+import space.arim.libertybans.core.env.EnvMessageChannel;
import space.arim.libertybans.core.env.EnvServerNameDetection;
import space.arim.libertybans.core.env.EnvUserResolver;
import space.arim.libertybans.core.env.Environment;
@@ -64,6 +65,10 @@ public EnvUserResolver envUserResolver(SpongeUserResolver resolver) {
return resolver;
}
+ public EnvMessageChannel> envMessageChannel(SpongeMessageChannel messageChannel) {
+ return messageChannel;
+ }
+
public EnvServerNameDetection serverNameDetection() {
return (scopeManager) -> {};
}
diff --git a/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/SpongeEnforcer.java b/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/SpongeEnforcer.java
index 9cf63d8fb..7fd1624d9 100644
--- a/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/SpongeEnforcer.java
+++ b/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/SpongeEnforcer.java
@@ -26,33 +26,31 @@
import org.spongepowered.api.Game;
import org.spongepowered.api.command.exception.CommandException;
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
-import org.spongepowered.api.network.channel.raw.play.RawPlayDataChannel;
import space.arim.api.env.AudienceRepresenter;
-import space.arim.libertybans.core.config.Configs;
import space.arim.libertybans.core.config.InternalFormatter;
import space.arim.libertybans.core.env.AbstractEnvEnforcer;
import space.arim.libertybans.core.env.Interlocutor;
-import space.arim.libertybans.core.env.message.KickPlayer;
+import space.arim.libertybans.core.env.message.PluginMessage;
import space.arim.omnibus.util.concurrent.CentralisedFuture;
import space.arim.omnibus.util.concurrent.FactoryOfTheFuture;
import java.net.InetAddress;
-import java.util.Optional;
+import java.util.Collection;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
public final class SpongeEnforcer extends AbstractEnvEnforcer {
- private final Configs configs;
private final Game game;
+ private final SpongeMessageChannel messageChannel;
@Inject
public SpongeEnforcer(FactoryOfTheFuture futuresFactory, InternalFormatter formatter,
- Interlocutor interlocutor, Configs configs, Game game) {
+ Interlocutor interlocutor, Game game, SpongeMessageChannel messageChannel) {
super(futuresFactory, formatter, interlocutor, AudienceRepresenter.identity());
- this.configs = configs;
this.game = game;
+ this.messageChannel = messageChannel;
}
@SuppressWarnings("unchecked")
@@ -62,8 +60,8 @@ private CentralisedFuture runSync(Runnable command) {
}
@Override
- protected CentralisedFuture doForAllPlayers(Consumer callback) {
- return runSync(() -> game.server().onlinePlayers().forEach(callback));
+ public CentralisedFuture doForAllPlayers(Consumer> callback) {
+ return runSync(() -> callback.accept(game.server().onlinePlayers()));
}
@Override
@@ -73,23 +71,14 @@ public CentralisedFuture doForPlayerIfOnline(UUID uuid, Consumer channel = PluginMessagingListener.findChannel(game);
- if (channel.isPresent()) {
- PluginMessagingListener.sendPluginMessage(
- channel.get(), player,
- new KickPlayer(), new KickPlayer.Data(player.name(), message)
- );
- return;
- }
- LoggerFactory.getLogger(getClass()).warn(
- "Kicking via plugin messaging is enabled, but the proper channel does not exist."
- );
- }
player.kick(message);
}
+ @Override
+ public boolean sendPluginMessageIfListening(ServerPlayer player, PluginMessage pluginMessage, D data) {
+ return messageChannel.sendPluginMessage(player, pluginMessage, data);
+ }
+
@Override
public UUID getUniqueIdFor(ServerPlayer player) {
return player.uniqueId();
@@ -100,6 +89,11 @@ public InetAddress getAddressFor(ServerPlayer player) {
return player.connection().address().getAddress();
}
+ @Override
+ public String getNameFor(ServerPlayer player) {
+ return player.name();
+ }
+
@Override
public boolean hasPermission(ServerPlayer player, String permission) {
return player.hasPermission(permission);
diff --git a/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/SpongeEnv.java b/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/SpongeEnv.java
index 3d93ba3ca..75dddc499 100644
--- a/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/SpongeEnv.java
+++ b/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/SpongeEnv.java
@@ -31,15 +31,15 @@ public final class SpongeEnv implements Environment {
private final Provider connectionListener;
private final Provider chatListener;
- private final Provider pluginMessagingListener;
+ private final Provider serverNameListener;
private final PlatformAccess platformAccess;
@Inject
public SpongeEnv(Provider connectionListener, Provider chatListener,
- Provider pluginMessagingListener, PlatformAccess platformAccess) {
+ Provider serverNameListener, PlatformAccess platformAccess) {
this.connectionListener = connectionListener;
this.chatListener = chatListener;
- this.pluginMessagingListener = pluginMessagingListener;
+ this.serverNameListener = serverNameListener;
this.platformAccess = platformAccess;
}
@@ -48,7 +48,7 @@ public Set createListeners() {
return Set.of(
connectionListener.get(),
chatListener.get(),
- pluginMessagingListener.get()
+ serverNameListener.get()
);
}
diff --git a/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/SpongeLauncher.java b/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/SpongeLauncher.java
index 3eba51a67..fc0d0a096 100644
--- a/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/SpongeLauncher.java
+++ b/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/SpongeLauncher.java
@@ -32,6 +32,7 @@
import space.arim.libertybans.core.CommandsModule;
import space.arim.libertybans.core.PillarOneBindModule;
import space.arim.libertybans.core.PillarTwoBindModule;
+import space.arim.libertybans.core.env.InstanceType;
import space.arim.libertybans.env.sponge.listener.RegisterListeners;
import space.arim.libertybans.env.sponge.listener.RegisterListenersByMethodScan;
import space.arim.libertybans.env.sponge.listener.RegisterListenersStandard;
@@ -86,6 +87,7 @@ public BaseFoundation launch() {
.bindInstance(PluginContainer.class, plugin)
.bindInstance(Game.class, game)
.bindInstance(Identifier.ofTypeAndNamed(Path.class, "folder"), folder)
+ .bindInstance(InstanceType.class, InstanceType.GAME_SERVER)
.bindInstance(Omnibus.class, omnibus)
.addBindModules(
new ApiBindModule(),
diff --git a/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/SpongeMessageChannel.java b/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/SpongeMessageChannel.java
new file mode 100644
index 000000000..3149bfe53
--- /dev/null
+++ b/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/SpongeMessageChannel.java
@@ -0,0 +1,110 @@
+/*
+ * LibertyBans
+ * Copyright © 2023 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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * LibertyBans 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with LibertyBans. If not, see
+ * and navigate to version 3 of the GNU Affero General Public License.
+ */
+
+package space.arim.libertybans.env.sponge;
+
+import jakarta.inject.Inject;
+import org.slf4j.LoggerFactory;
+import org.spongepowered.api.Game;
+import org.spongepowered.api.ResourceKey;
+import org.spongepowered.api.entity.living.player.server.ServerPlayer;
+import org.spongepowered.api.network.EngineConnectionSide;
+import org.spongepowered.api.network.ServerSideConnection;
+import org.spongepowered.api.network.channel.ChannelBuf;
+import org.spongepowered.api.network.channel.raw.RawDataChannel;
+import org.spongepowered.api.network.channel.raw.play.RawPlayDataChannel;
+import org.spongepowered.api.network.channel.raw.play.RawPlayDataHandler;
+import space.arim.libertybans.core.env.EnvMessageChannel;
+import space.arim.libertybans.core.env.message.PluginMessage;
+import space.arim.libertybans.core.env.message.PluginMessageInput;
+import space.arim.libertybans.core.env.message.PluginMessageOutput;
+
+import java.io.IOException;
+import java.util.function.Consumer;
+
+public final class SpongeMessageChannel implements EnvMessageChannel> {
+
+ private final Game game;
+
+ @Inject
+ public SpongeMessageChannel(Game game) {
+ this.game = game;
+ }
+
+ private RawPlayDataChannel channel() {
+ return game.channelManager()
+ .ofType(ResourceKey.of("bungeecord", "main"), RawDataChannel.class)
+ .play();
+ }
+
+ boolean sendPluginMessage(ServerPlayer player, PluginMessage pluginMessage, D data) {
+ var channel = channel();
+ boolean supported = channel.isSupportedBy(player.connection());
+ if (supported) {
+ channel.sendTo(player, (buffer) -> {
+ pluginMessage.writeTo(data, new ChannelBufAsOutput(buffer));
+ }).exceptionally((ex) -> {
+ LoggerFactory.getLogger(getClass()).error("Failed to send plugin message", ex);
+ return null;
+ });
+ }
+ return supported;
+ }
+
+ @Override
+ public void installHandler(RawPlayDataHandler handler) {
+ channel().addHandler(EngineConnectionSide.SERVER, handler);
+ }
+
+ @Override
+ public void uninstallHandler(RawPlayDataHandler handler) {
+ channel().removeHandler(handler);
+ }
+
+ @Override
+ public RawPlayDataHandler createHandler(Consumer acceptor,
+ PluginMessage, R> pluginMessage) {
+ return new Handler<>(acceptor, pluginMessage);
+ }
+
+ record Handler(Consumer handler, PluginMessage, R> pluginMessage)
+ implements RawPlayDataHandler {
+
+ @Override
+ public void handlePayload(ChannelBuf data, ServerSideConnection connection) {
+ pluginMessage.readFrom(new ChannelBufAsInput(data)).ifPresent(handler);
+ }
+
+ }
+
+ private record ChannelBufAsOutput(ChannelBuf buffer) implements PluginMessageOutput {
+ @Override
+ public void writeUTF(String utf) throws IOException {
+ buffer.writeUTF(utf);
+ }
+ }
+
+ private record ChannelBufAsInput(ChannelBuf buffer) implements PluginMessageInput {
+ @Override
+ public String readUTF() throws IOException {
+ return buffer.readUTF();
+ }
+ }
+
+}
diff --git a/bans-env/standalone/src/main/java/space/arim/libertybans/env/standalone/StandaloneBindModule.java b/bans-env/standalone/src/main/java/space/arim/libertybans/env/standalone/StandaloneBindModule.java
index 00c565b14..0fe377a0a 100644
--- a/bans-env/standalone/src/main/java/space/arim/libertybans/env/standalone/StandaloneBindModule.java
+++ b/bans-env/standalone/src/main/java/space/arim/libertybans/env/standalone/StandaloneBindModule.java
@@ -23,6 +23,7 @@
import space.arim.api.env.PlatformHandle;
import space.arim.api.env.PlatformPluginInfo;
import space.arim.libertybans.core.env.EnvEnforcer;
+import space.arim.libertybans.core.env.EnvMessageChannel;
import space.arim.libertybans.core.env.EnvServerNameDetection;
import space.arim.libertybans.core.env.EnvUserResolver;
import space.arim.libertybans.core.env.Environment;
@@ -82,6 +83,10 @@ public EnvUserResolver resolver(StandaloneResolver resolver) {
return resolver;
}
+ public EnvMessageChannel> messageChannel(EnvMessageChannel.NoOp messageChannel) {
+ return messageChannel;
+ }
+
public EnvServerNameDetection serverNameDetection() {
return (scopeManager) -> scopeManager.detectServerName("standalone");
}
diff --git a/bans-env/standalone/src/main/java/space/arim/libertybans/env/standalone/StandaloneEnforcer.java b/bans-env/standalone/src/main/java/space/arim/libertybans/env/standalone/StandaloneEnforcer.java
index b236be032..0332646a0 100644
--- a/bans-env/standalone/src/main/java/space/arim/libertybans/env/standalone/StandaloneEnforcer.java
+++ b/bans-env/standalone/src/main/java/space/arim/libertybans/env/standalone/StandaloneEnforcer.java
@@ -25,10 +25,12 @@
import net.kyori.adventure.text.ComponentLike;
import space.arim.libertybans.core.env.EnvEnforcer;
import space.arim.libertybans.core.env.TargetMatcher;
+import space.arim.libertybans.core.env.message.PluginMessage;
import space.arim.omnibus.util.concurrent.CentralisedFuture;
import space.arim.omnibus.util.concurrent.FactoryOfTheFuture;
import java.net.InetAddress;
+import java.util.Collection;
import java.util.UUID;
import java.util.function.Consumer;
@@ -53,11 +55,21 @@ public CentralisedFuture doForPlayerIfOnline(UUID uuid, Consumer cal
return completedVoid();
}
+ @Override
+ public CentralisedFuture doForAllPlayers(Consumer> action) {
+ return completedVoid();
+ }
+
@Override
public void kickPlayer(Void player, Component message) {
throw new UnsupportedOperationException();
}
+ @Override
+ public boolean sendPluginMessageIfListening(Void player, PluginMessage pluginMessage, D data) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public void sendMessageNoPrefix(Void player, ComponentLike message) {
throw new UnsupportedOperationException();
diff --git a/bans-env/standalone/src/main/java/space/arim/libertybans/env/standalone/StandaloneLauncher.java b/bans-env/standalone/src/main/java/space/arim/libertybans/env/standalone/StandaloneLauncher.java
index 36aba259f..0a6a15630 100644
--- a/bans-env/standalone/src/main/java/space/arim/libertybans/env/standalone/StandaloneLauncher.java
+++ b/bans-env/standalone/src/main/java/space/arim/libertybans/env/standalone/StandaloneLauncher.java
@@ -31,6 +31,7 @@
import space.arim.libertybans.core.PillarOneBindModule;
import space.arim.libertybans.core.PillarTwoBindModule;
import space.arim.libertybans.core.addon.AddonLoader;
+import space.arim.libertybans.core.env.InstanceType;
import space.arim.omnibus.Omnibus;
import space.arim.omnibus.OmnibusProvider;
@@ -53,6 +54,7 @@ public StandaloneLauncher(Path folder, Omnibus omnibus) {
public Injector createInjector(ConsoleAudience consoleAudience) {
return new InjectorBuilder()
.bindInstance(Identifier.ofTypeAndNamed(Path.class, "folder"), folder)
+ .bindInstance(InstanceType.class, InstanceType.STANDALONE)
.bindInstance(Omnibus.class, omnibus)
.bindInstance(ConsoleAudience.class, consoleAudience)
.addBindModules(
diff --git a/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/VelocityBindModule.java b/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/VelocityBindModule.java
index ad3a9117f..180fee720 100644
--- a/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/VelocityBindModule.java
+++ b/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/VelocityBindModule.java
@@ -25,6 +25,7 @@
import space.arim.api.env.PlatformHandle;
import space.arim.api.env.velocity.VelocityPlatformHandle;
import space.arim.libertybans.core.env.EnvEnforcer;
+import space.arim.libertybans.core.env.EnvMessageChannel;
import space.arim.libertybans.core.env.EnvServerNameDetection;
import space.arim.libertybans.core.env.EnvUserResolver;
import space.arim.libertybans.core.env.Environment;
@@ -55,6 +56,10 @@ public EnvUserResolver resolver(VelocityUserResolver resolver) {
return resolver;
}
+ public EnvMessageChannel> messageChannel(VelocityMessageChannel messageChannel) {
+ return messageChannel;
+ }
+
public EnvServerNameDetection serverNameDetection() {
return (scopeManager) -> scopeManager.detectServerName("proxy");
}
diff --git a/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/VelocityEnforcer.java b/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/VelocityEnforcer.java
index 2a01f0d64..d3ec72758 100644
--- a/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/VelocityEnforcer.java
+++ b/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/VelocityEnforcer.java
@@ -1,6 +1,6 @@
/*
* LibertyBans
- * Copyright © 2022 Anand Beh
+ * Copyright © 2023 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
@@ -30,10 +30,12 @@
import space.arim.libertybans.core.config.InternalFormatter;
import space.arim.libertybans.core.env.AbstractEnvEnforcer;
import space.arim.libertybans.core.env.Interlocutor;
+import space.arim.libertybans.core.env.message.PluginMessage;
import space.arim.omnibus.util.concurrent.CentralisedFuture;
import space.arim.omnibus.util.concurrent.FactoryOfTheFuture;
import java.net.InetAddress;
+import java.util.Collection;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
@@ -42,17 +44,19 @@
public class VelocityEnforcer extends AbstractEnvEnforcer {
private final ProxyServer server;
+ private final VelocityMessageChannel messageChannel;
@Inject
public VelocityEnforcer(FactoryOfTheFuture futuresFactory, InternalFormatter formatter,
- Interlocutor interlocutor, ProxyServer server) {
+ Interlocutor interlocutor, ProxyServer server, VelocityMessageChannel messageChannel) {
super(futuresFactory, formatter, interlocutor, AudienceRepresenter.identity());
this.server = server;
+ this.messageChannel = messageChannel;
}
@Override
- protected CentralisedFuture doForAllPlayers(Consumer callback) {
- server.getAllPlayers().forEach(callback);
+ public CentralisedFuture doForAllPlayers(Consumer> callback) {
+ callback.accept(server.getAllPlayers());
return completedVoid();
}
@@ -61,6 +65,12 @@ public void kickPlayer(Player player, Component message) {
player.disconnect(message);
}
+ @Override
+ public boolean sendPluginMessageIfListening(Player player, PluginMessage pluginMessage, D data) {
+ messageChannel.sendPluginMessage(player, pluginMessage, data);
+ return true;
+ }
+
@Override
public CentralisedFuture doForPlayerIfOnline(UUID uuid, Consumer callback) {
server.getPlayer(uuid).ifPresent(callback);
@@ -77,6 +87,11 @@ public InetAddress getAddressFor(Player player) {
return player.getRemoteAddress().getAddress();
}
+ @Override
+ public String getNameFor(Player player) {
+ return player.getUsername();
+ }
+
@Override
public boolean hasPermission(Player player, String permission) {
return player.hasPermission(permission);
diff --git a/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/VelocityLauncher.java b/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/VelocityLauncher.java
index 664654325..f1cb1e208 100644
--- a/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/VelocityLauncher.java
+++ b/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/VelocityLauncher.java
@@ -1,6 +1,6 @@
/*
* LibertyBans
- * Copyright © 2022 Anand Beh
+ * Copyright © 2023 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,6 +31,7 @@
import space.arim.libertybans.core.PillarOneBindModule;
import space.arim.libertybans.core.PillarTwoBindModule;
import space.arim.libertybans.core.addon.AddonLoader;
+import space.arim.libertybans.core.env.InstanceType;
import space.arim.omnibus.Omnibus;
import space.arim.omnibus.OmnibusProvider;
@@ -60,6 +61,7 @@ public BaseFoundation launch() {
.bindInstance(PluginContainer.class, plugin)
.bindInstance(ProxyServer.class, server)
.bindInstance(Identifier.ofTypeAndNamed(Path.class, "folder"), folder)
+ .bindInstance(InstanceType.class, InstanceType.PROXY)
.bindInstance(Omnibus.class, omnibus)
.addBindModules(
new ApiBindModule(),
diff --git a/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/VelocityMessageChannel.java b/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/VelocityMessageChannel.java
new file mode 100644
index 000000000..38addb156
--- /dev/null
+++ b/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/VelocityMessageChannel.java
@@ -0,0 +1,84 @@
+/*
+ * LibertyBans
+ * Copyright © 2023 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
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * LibertyBans 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with LibertyBans. If not, see
+ * and navigate to version 3 of the GNU Affero General Public License.
+ */
+
+package space.arim.libertybans.env.velocity;
+
+import com.velocitypowered.api.event.EventHandler;
+import com.velocitypowered.api.event.connection.PluginMessageEvent;
+import com.velocitypowered.api.plugin.PluginContainer;
+import com.velocitypowered.api.proxy.Player;
+import com.velocitypowered.api.proxy.ProxyServer;
+import com.velocitypowered.api.proxy.ServerConnection;
+import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
+import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
+import jakarta.inject.Inject;
+import space.arim.libertybans.core.env.EnvMessageChannel;
+import space.arim.libertybans.core.env.PluginMessageAsBytes;
+import space.arim.libertybans.core.env.message.PluginMessage;
+
+import java.util.function.Consumer;
+
+public final class VelocityMessageChannel implements EnvMessageChannel> {
+
+ private final PluginContainer plugin;
+ private final ProxyServer server;
+
+ private static final ChannelIdentifier BUNGEE_CHANNEL = MinecraftChannelIdentifier.create("bungeecord", "main");
+
+ @Inject
+ public VelocityMessageChannel(PluginContainer plugin, ProxyServer server) {
+ this.plugin = plugin;
+ this.server = server;
+ }
+
+ void sendPluginMessage(Player player, PluginMessage pluginMessage, D data) {
+ player.getCurrentServer().ifPresent((server) -> {
+ server.sendPluginMessage(
+ BUNGEE_CHANNEL,
+ new PluginMessageAsBytes<>(pluginMessage).generateBytes(data)
+ );
+ });
+ }
+
+ @Override
+ public void installHandler(EventHandler handler) {
+ server.getEventManager().register(plugin, PluginMessageEvent.class, handler);
+ }
+
+ @Override
+ public void uninstallHandler(EventHandler handler) {
+ server.getEventManager().unregister(plugin, handler);
+ }
+
+ @Override
+ public EventHandler createHandler(Consumer acceptor, PluginMessage, R> pluginMessage) {
+ class AsHandler implements EventHandler {
+
+ @Override
+ public void execute(PluginMessageEvent event) {
+ if (event.getSource() instanceof ServerConnection && event.getIdentifier().equals(BUNGEE_CHANNEL)) {
+ new PluginMessageAsBytes<>(pluginMessage)
+ .readBytes(event.getData())
+ .ifPresent(acceptor);
+ }
+ }
+ }
+ return new AsHandler();
+ }
+}
diff --git a/docs/Comparison-to-LiteBans.md b/docs/Comparison-to-LiteBans.md
index d729ea908..131d055a8 100644
--- a/docs/Comparison-to-LiteBans.md
+++ b/docs/Comparison-to-LiteBans.md
@@ -96,6 +96,8 @@ LiteBans' support for Velocity came after repeated user requests. It was suggest
LibertyBans and LiteBans have Geyser support.
+However, documentation suggests LiteBans requires the prefix to be the period character (".").[4](#note4)
+
### Core punishment types
Both LibertyBans and LiteBans include bans, ip-bans, mutes, warns, and kicks.
@@ -128,7 +130,7 @@ LiteBans supports importing from AdvancedBan, BanManager, BungeeAdminTools, MaxB
Both plugins enable punishments scoped to certain servers.
-However, LiteBans lacks scope categories, or the ability to group servers into a single scope.[4](#note4)
+However, LiteBans lacks scope categories, or the ability to group servers into a single scope.[5](#note5)
### Multi-Proxy / Multi-Instance Synchronization
@@ -142,7 +144,9 @@ Both LibertyBans and LiteBans provide synchronization across multiple instances,
3: Ruan. "[Feature] Spongepowered?". LiteBans Gitlab Issue comment. https://gitlab.com/ruany/LiteBans/-/issues/41#note_324182783 [↩](#note3ret)
-4: lewisakura. "Server scope groups". LiteBans Gitlab Issue. https://gitlab.com/ruany/LiteBans/-/issues/452
+4: Ruan. "LiteBans 2.7.5 (Connection error fix)". SpigotMC Resource Update. https://www.spigotmc.org/resources/litebans.3715/update?update=414133
+
+5: lewisakura. "Server scope groups". LiteBans Gitlab Issue. https://gitlab.com/ruany/LiteBans/-/issues/452
### Disclaimer
diff --git a/docs/Quick-Plugin-Comparison.md b/docs/Quick-Plugin-Comparison.md
index beca41a12..361307a0e 100644
--- a/docs/Quick-Plugin-Comparison.md
+++ b/docs/Quick-Plugin-Comparison.md
@@ -1,4 +1,4 @@
-This is a quick table for comparing between LibertyBans, AdvancedBan, and LiteBans.
+This is a quick table for comparing between LibertyBans, AdvancedBan, BanManager, and LiteBans.
**NB: *Tables and graphs do not tell the full picture!*** To really understand what's going on here, read the detailed and explanatory
comparisons. You can find these on the sidebar at the right. For each plugin here, there is a detailed comparison between LibertyBans and the plugin.
@@ -16,19 +16,19 @@ comparisons. You can find these on the sidebar at the right. For each plugin her
[GPL]:https://www.gnu.org/graphics/gplv3-127x51.png
[CC-BY-NC]:http://mirrors.creativecommons.org/presskit/buttons/88x31/png/by-nc.png
-| Plugin | Supported Platforms | Java Req. | Free (Gratis) | Open License | Database Support | Thread-Safe Design | Stable API | Geyser Support | Multi-Instance Support | Connection Pool | Exemption | Server Scopes | Uses UUIDs | Schema Integrity | Import From |
-|-------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|---------------|----------------|--------------------------------------------|--------------------|------------|----------------|------------------------|-----------------|-----------|---------------|------------|------------------|---------------------------------------------------------------------------------------|
-| LibertyBans | ![Bukkit]Bukkit
Bungee
Sponge Velocity | 17+ | ✔️ | ✔️ ![AGPL] | HSQLDB (local), MariaDB, MySQL, PostgreSQL | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | AdvancedBan
BanManager
LiteBans
vanilla |
-| AdvancedBan | ![Bukkit]Bukkit
Bungee | 8+ | ✔️ | ✔️ ![GPL] | HSQLDB (local), MariaDB, MySQL | ❌ | ❌ | ❓ | ❌ | ❌ | ✔️ | ❌ | ➖ | ❌ | |
-| BanManager | ![Bukkit]Bukkit
Bungee
Sponge | 8+ | ✔️ | ➖️ ![CC-BY-NC] | H2 (local), MariaDB, MySQL | ❌️ | ❌ | ➖ | ✔️ | ✔️ | ❌ | ➖ | ✔️ | ✔️ | AdvancedBan
vanilla |
-| LiteBans | ![Bukkit]Bukkit
Bungee
Velocity | 8+ | ❌ | ❌ Proprietary | H2 (local), MariaDB, MySQL, PostgreSQL | ❓ | ➖ | ✔️ | ✔️ | ❓ | ✔️ | ➖ | ✔️ | ❌ | AdvancedBan
BanManager
BungeeAdminTools
MaxBans
UltraBans
vanilla |
-| vanilla | ![Bukkit]Bukkit
Sponge | 8+ | ✔️ | ❌ Proprietary | Flatfile | ✔️ | ✔️ | ✔️ | ❌ | NA | ❌ | ❌ | ✔️ | ❌ | |
+| Plugin | Supported Platforms | Java Req. | Free (Gratis) | Open License | Debuggable, Modifiable | Databases Available | Thread-Safe Design | Stable API | Geyser Support | Multi-Instance Support | Connection Pool | Exemption | Server Scopes | Uses UUIDs | Schema Integrity | Switch Storage Backends | Import From |
+|-------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|---------------|-----------------|------------------------|--------------------------------------------|--------------------|------------|----------------|------------------------|-----------------|-----------|---------------|------------|------------------|-------------------------|--------------------------------------------------------------------------------------------------------------------------------|
+| LibertyBans | ![Bukkit]Bukkit
Bungee
Sponge Velocity | 17+ | ✔️ | ✔️ ![AGPL] | ✔️ | HSQLDB (local), MariaDB, MySQL, PostgreSQL | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | AdvancedBan
BanManager
LiteBans
vanilla |
+| AdvancedBan | ![Bukkit]Bukkit
Bungee | 8+ | ✔️ | ✔️ ![GPL] | ✔️ | HSQLDB (local), MariaDB, MySQL | ❌ | ❌ | ❓ | ❌ | ❌ | ✔️ | ❌ | ➖️ | ❌ | ❌ | |
+| BanManager | ![Bukkit]Bukkit
Bungee
Sponge | 8+ | ✔️ | ➖️️ ![CC-BY-NC] | ✔️ | H2 (local), MariaDB, MySQL | ❌️ | ❌ | ➖️️ | ✔️ | ✔️ | ❌ | ➖️ | ✔️ | ✔️ | ➖️ | AdvancedBan
vanilla |
+| LiteBans | ![Bukkit]Bukkit
Bungee
Velocity | 8+ | ❌ | ❌ Proprietary | ❌ Obfuscated | H2 (local), MariaDB, MySQL, PostgreSQL | ❓ | ➖️ | ➖️️ | ✔️ | ❓ | ✔️ | ➖️ | ✔️ | ❌ | ✔️ | AdvancedBan
BanHammer**
BanManager
BungeeAdminTools**
LibertyBans ➖️
MaxBans**
UltraBans**
vanilla |
+| vanilla | ![Bukkit]Bukkit
Sponge | 8+ | ✔️ | ❌ Proprietary | NA | Flatfile | ✔️ | ✔️ | ✔️ | ❌ | NA | ❌ | ❌ | ✔️ | ❌ | NA | |
Legend:
✔️ – Yes
-➖ – Partially
+➖️ – Partially
❌ – No
@@ -36,6 +36,16 @@ Legend:
NA - Not applicable
+** - This plugin has been abandoned for at least 3 years.
+
+### Why does LibertyBans check all the boxes?
+
+It didn't used to. This chart was created when LibertyBans didn't have multi-instance support, exemption, server scopes, or switching storage backends. With this exception of switching storage, all these features were listed in the table, but they were unimplemented and unrequested -- with no plans to add them! Back then, LibertyBans used to receive ❌ or ➖️ in many areas.
+
+Over time, features were requested and implemented, so LibertyBans fulfills these categories now and receives ✔️. Competitor plugins still have capabilities not found in LibertyBans, but they aren't deemed sufficiently important or central to the purpose of punishment to have a place on the table.
+
+How do we know the features listed in the table are sufficiently important and central to the purpose of a punishment plugin? Well, in most cases, we *predicted* which features would be most important, so we placed them in the table. The predictions turned out to be correct, since the categories in the table were the most popular feature requests.
+
## Categories
Some categories require further explanation because they are not self-explanatory. They are described here.
@@ -60,6 +70,14 @@ BanManager's license prohibits commercial use. This makes it **illegal** to use
Disclaimer: This is not legal advice and the writer is not a lawyer.
+### Debuggable, Modifiable
+
+Whether the plugin can be debugged by users and modified by developers.
+* Debugging is a critical tool because it allows administrators to fix problems deep in the software stack. This remains true regardless of whether a plugin is at fault for the bug.
+* Modifying a plugin safeguards user and developer freedom. It provides an escape hatch if the original author is unwilling to implement a feature or a workaround.
+
+LiteBans is obfuscated, meaning its plugin jar is intentionally scrambled to prevent anyone from inspecting its operations or making any sort of modification.
+
### Thread-Safe Design
If a plugin is not thread-safe, it will have unreliable and buggy behavior. However, some of this unreliable behavior may only occur in exceptional and rare circumstances, making it very hard to debug and diagnose.
@@ -74,6 +92,12 @@ See [semver.org](https://semver.org/) and the detailed plugin-specific compariso
LiteBans' *partial* ranking: LiteBans follows the semver constraint of restricting breaking changes to major versions, but does not follow semver for additions of new API, which *should* be done in minor releases.
+### Geyser Support
+
+Whether the plugin is compatible with Geyser/Floodgate, a plugin which allows Bedrock Edition players to join the server or proxy by changing usernames.
+
+LiteBans' *partial* ranking: LiteBans claims Geyser compatibility, but its documentation suggests the period character is the only supported prefix for Bedrock usernames.
+
### Multi-Instance Support
This feature allows synchronizing punishments across multiple instances of the given plugin. It is relevant for proxies.
@@ -106,3 +130,19 @@ Whether the data types defined by the plugin's database schema have appropriate
* Otherwise, bugs in the plugin may corrupt user data.
Data corruption, if it occurs, is not easy to recover from and may require manually interfacing with the database.
+
+### Switch Storage Backends
+
+Whether the user can switch between the supported database backends. This feature is also known as "self-importing."
+
+BanManager's *partial* ranking: BanManager only supports converting from H2 to MySQL/MariaDB, but it is not possible to switch back to H2.
+
+### Import From
+
+The other punishment suites this plugin can import from.
+
+LiteBans' *partial* ranking with respect to LibertyBans: LiteBans does not import server scopes, although scopes are a common feature between them.
+
+--------------------------------------------------------------------------
+
+As a closing note, this information is kept up-to-date within a reasonable timeframe. We welcome PRs from those affiliated with other plugins to update this information when necessary.